拓冰建站拓冰建站
首页 / 资讯中心 / 正文

OpenWork Den API 的 /v1/me 路由:当前认证用户与活跃组织的实现指南

OpenWork Den API 的 /v1/me 路由当前认证用户与活跃组织的实现指南【免费下载链接】openworkThe open-source alternative to Claude Cowork (powered by opencode)项目地址: https://gitcode.com/GitHub_Trending/ope/openwork本指南以 ee/apps/den-api/src/routes/me/README.md 为骨架深入剖析 Den API 中负责当前登录用户current actor的me路由模块它注册了/v1/me与/v1/me/orgs两个端点并围绕返回当前用户/会话负载、解析当前用户所属组织、暴露当前会话的活跃组织选择数据三项职责展开。读完本文你将掌握 me 模块的路由清单、鉴权中间件选型、活跃组织解析逻辑、限流与错误处理细节以及如何在现有代码结构上继续扩展当前用户相关子域。一、模块定位只服务当前用户这一角色me文件夹是 Den API 中对当前认证用户the currently authenticated user相关路由的归属地。它的边界非常清晰只面向当前 actor调用者自己不做任何任意的用户管理操作如管理员查看/修改他人资料。这一边界被明确记录在 README 的 Notes for future work 中保持该文件夹聚焦于当前 actor而非任意的用户管理操作如果后续出现更多当前用户子区域应在本文件夹内拆分为独立文件而不是塞进index.ts或别处。从源码结构看目前该文件夹只有两个文件README.md 与 index.ts其中index.ts是唯一的实现文件负责注册/v1/me与/v1/me/orgs。按 README 的规划未来若出现新的当前用户子域例如我的通知设置、我的设备应拆成me/profile.ts、me/devices.ts之类的额外文件保持单一职责。二、路由清单与三项核心职责2.1 README 声明的职责README 将模块职责归纳为三点返回当前认证的用户/会话负载return the current authenticated user/session payload解析当前用户所属的组织resolve the orgs the current user belongs to暴露当前会话的活跃组织选择数据expose active org selection data for the current session。2.2 实际实现五个端点对照 index.ts 的实际注册代码registerMeRoutes共挂载了五个路由README 只点名了前两个后三个是模块演化后的实际扩展全部归属同一主题域方法路径中间件职责GET/v1/meauthenticatedRoute()返回当前用户与活跃会话详情GET/v1/me/orgsorgMemberRoute({ useUserOrganizations: true })列出当前用户可见的组织并标记活跃组织POST/v1/me/send-download-linkauthenticatedRoute()向当前用户邮箱发送桌面端下载链接PATCH/v1/me/profileauthenticatedRoute()jsonValidator(updateProfileSchema)更新当前用户的显示姓名POST/v1/me/active-organizationuserSessionRoute()jsonValidator(setActiveOrganizationSchema)为当前会话切换活跃组织hide: true仅内部使用GET/v1/me/desktop-configorgMemberRoute()返回当前用户活跃组织的桌面端限制配置所有路由在 Hono OpenAPI 描述中都被标记为tags: [Users]。注册入口位于 app.ts 的 registerMeRoutes(app)与registerOrgRoutes、registerVersionRoutes、registerWebhookRoutes等并列挂载到同一 Hono 应用上。三、中间件选型authenticatedRoute 与 orgMemberRouteREADME 的Middleware expectations一节给出了两条铁律路由需要已认证用户时使用requireUserMiddleware路由需要组织成员上下文时使用resolveUserOrganizationsMiddleware。在 Den API 中这些底层中间件被封装成了更语义化的路由守卫定义于 middleware/route-access.tsexport function authenticatedRoute(): MiddlewareHandler{ Variables: AuthContextVariables } { return requireUserMiddleware } export function userSessionRoute(): MiddlewareHandler{ Variables: AuthContextVariables } { return requireUserSessionMiddleware } export function orgMemberRoute(options: { useUserOrganizations: true }): typeof resolveUserOrganizationsMiddleware export function orgMemberRoute(): typeof resolveOrganizationContextMiddleware export function orgMemberRoute(options?: { useUserOrganizations: true }) { if (options?.useUserOrganizations) { return resolveUserOrganizationsMiddleware } return resolveOrganizationContextMiddleware }3.1 requireUserMiddleware最基础的登录校验实现位于 middleware/current-user.ts只检查c.get(user)?.id是否存在不存在则直接返回401 { error: unauthorized }。这是 me 模块大多数端点的最小鉴权因为它只需要这个人登录了不需要组织上下文。3.2 requireUserSessionMiddleware要求真实的用户会话与requireUserMiddleware不同userSessionRoute()背后的 requireUserSessionMiddleware 在用户已认证的基础上还额外要求请求不能是 API Key 调用c.get(apiKey)为空会话必须存在且携带 token会话 ID 必须能通过normalizeDenTypeId(session, ...)的类型校验。任一条件不满足返回403。这正是/v1/me/active-organization使用它的原因切换活跃组织是会话级操作只允许带登录会话的客户端执行API Key 与无 token 的调用一律拒绝详见 index.ts 中的路由描述This is used by desktop bearer-token sessions that cannot call Better Auths cookie-backed organization endpoint.。3.3 resolveUserOrganizationsMiddleware组织成员上下文这是 me 模块中信息量最大的中间件实现在 middleware/user-organizations.ts。它的执行流程校验用户已认证无 user 直接 401解析组织作用域来源优先级为API Key 绑定的组织getApiKeyScopedOrganizationId→ 请求头x-openwork-org-idORG_SCOPE_HEADER→ 遗留头x-openwork-legacy-org-idLEGACY_ORG_PROXY_HEADER调用resolveUserOrganizations解析用户可见组织与活跃组织若存在作用域组织将组织列表过滤为仅该组织若会话尚未持久化活跃组织且可解析出活跃组织则调用hydrateSessionActiveOrganization回写会话保证首次进入组织时会话状态自愈在 Hono context 中写入userOrganizations、activeOrganizationId、activeOrganizationSlug三个变量。/v1/me/orgs使用orgMemberRoute({ useUserOrganizations: true })正是为了获得上述三个 context 变量来组装响应/v1/me/desktop-config则使用不带参数的orgMemberRoute()即resolveOrganizationContextMiddleware因为桌面配置需要的是当前组织 当前成员的完整上下文organizationContext.organization与organizationContext.currentMember。3.4 路由守卫的显式注册检查值得注意的是 route-access.ts 的 explicitAuthGuardHandlers 用WeakSet显式登记了requireUserMiddleware、requireUserSessionMiddleware、resolveOrganizationContextMiddleware、resolveUserOrganizationsMiddleware等守卫并配合hasExplicitAuthGuardHandler做审计防止路由悄悄绕过鉴权。这说明 me 模块采用的中间件不仅是行为约定还处于 Den API 的鉴权静态检查体系之内。四、GET /v1/me当前用户与登录方式汇总该端点index.ts 第 150-183 行在authenticatedRoute()保护下返回{ user: { ...用户字段..., authProviders: [email, sso] }, session: { ...当前会话字段... } }实现细节中值得注意的两点authProviders 的推导路由查询AuthAccountTable中该用户的所有账号取providerId去重排序再经 normalizeAuthProvider 归一化credential/email-password→emailopenwork-sso-*→ssoopenwork-scim-*→scim其余原样返回。客户端据此可判断该用户是通过邮箱密码、企业 SSO 还是 SCIM 开通的账号。响应 SchemameResponseSchemaCurrentUserResponse对user与session采用z.object({}).passthrough()即验证结构但放行额外字段避免未来新增字段时破坏兼容。五、GET /v1/me/orgs组织列表与活跃标记该端点index.ts 第 185-209 行返回当前用户可见的组织并标注哪个组织处于活跃状态{ orgs: [ { id: ..., name: ..., slug: ..., ...: ..., isActive: true } ], activeOrgId: org_..., activeOrgSlug: acme }响应中每个组织的isActive由org.id c.get(activeOrganizationId)计算得出activeOrgId/activeOrgSlug直接来自resolveUserOrganizationsMiddleware写入的 context 变量未解析到时为null。底层组织解析逻辑在 orgs.ts 的 resolveUserOrganizations先调用ensureUserOrgAccess确保用户具备组织访问资格若部署为single_org模式env.orgMode single_org只保留 slug 等于env.singleOrg.slug的那个组织其他一律过滤活跃组织的判定优先级请求携带的activeOrganizationId须属于可见组织→ 若可见组织恰好只有一个则自动以该组织为活跃组织。多组织模式multi_org下活跃组织来自会话的activeOrganizationId或请求作用域头。DEN_ORG_MODE环境变量的解析规则见 env.ts 的 parseDenOrgMode未设置时默认single_org只接受single_org与multi_org两个取值其他值直接抛错。六、PATCH /v1/me/profile更新显示姓名该端点index.ts 第 268-304 行用于更新当前用户的显示姓名请求体 Schema 为 updateProfileSchemaconst updateProfileSchema z.object({ firstName: z.string().trim().max(120), lastName: z.string().trim().max(120), }).refine((value) value.firstName.length 0 || value.lastName.length 0, { message: Enter a first or last name., })校验要点两个字段均可选但至少填一个refine兜底每个字段最长 120 字符自动trim()服务端通过normalizeNamePart将连续空白折叠为单个空格再以[firstName, lastName].filter(Boolean).join( )拼接成完整name写入AuthUserTable更新后调用cache.auth.deleteSessionsForUser使该用户的会话缓存失效保证后续请求立刻读到新名字响应直接回显新的name与updatedAt。七、POST /v1/me/send-download-link桌面端下载链接发送该端点index.ts 第 211-266 行向当前用户邮箱发送桌面端下载链接用于桌面端登录后自助获取安装包。它集中体现了 me 模块的错误处理设计值得完整列出400— 账号缺少邮箱{ error: user_email_required }user.email?.trim()为空时返回。429— 限流核心参数定义在文件顶部const DOWNLOAD_LINK_RATE_LIMIT_WINDOW_MS 60 * 60 * 1000 // 1 小时窗口 const DOWNLOAD_LINK_RATE_LIMIT_MAX 5 // 最多 5 次限流实现为 checkDownloadLinkRateLimit以me:send-download-link:${userId}为 key 写入RateLimitTable窗口内计数达到 5 次即拒绝并在响应头返回Retry-After秒数。窗口滚动逻辑距上次请求超过 1 小时则计数重置为 1否则累加。502— 邮件发送失败捕获DenEmailSendError按error.reason细分错误信息reason含义email_not_configured部署未配置邮件服务resend_rejectedResend 拒绝投递含error.detail详情resend_network无法连接 Resendnodemailer_rejectedNodemailer 拒绝投递邮件走sendEmail工具使用downloadLink模板并注入downloadUrl: OPENWORK_DOWNLOAD_URL。非DenEmailSendError的异常会被重新抛出交由全局错误处理。八、POST /v1/me/active-organization会话级活跃组织切换该端点index.ts 第 306-352 行被describeRoute标记为hide: true不出现在公开 API 文档中专门服务于无法调用 Better Auth cookie 组织端点的桌面 bearer-token 会话。请求体支持二选一const setActiveOrganizationSchema z.object({ organizationId: denTypeIdSchema(organization).optional(), organizationSlug: z.string().trim().min(1).max(255).optional(), }).refine((value) value.organizationId ! undefined || value.organizationSlug ! undefined, { message: Provide an organization id or slug., })切换逻辑的关键在于归属校验与单组织模式的收紧先调用resolveUserOrganizations解析目标组织single_org模式下走 getAllowedSingleOrgActiveOrganization若用户只有一个组织且请求的组织 ID/Slug 与该组织一致或未指定才允许激活否则返回null触发 403multi_org模式下按请求的organizationId或organizationSlug在用户可见组织中查找未找到匹配组织 →403 { error: forbidden, message: You do not have access to this organization. }匹配成功 → 调用 setSessionActiveOrganization 将activeOrganizationId持久化到AuthSessionTable并同步更新当前 Hono context 中的 session响应返回{ activeOrgId, activeOrgSlug }。相关行为在 test/bearer-session.test.ts 中有测试覆盖使用x-api-key调用/v1/me/active-organization时由于userSessionRoute()拒绝 API Key期望得到 403。九、GET /v1/me/desktop-config活跃组织的桌面端策略该端点index.ts 第 354-399 行返回桌面端应用在当前活跃组织下应遵守的配置响应 Schema 为desktopConfigSchemaCurrentUserDesktopConfigResponse。其组装逻辑从organizationContext取出organization与currentMember调用normalizeOrganizationMetadata规范化组织元数据调用 calculateDesktopPolicyForOrgMember 计算该成员生效的桌面策略desktop-policies.ts同目录——例如策略版本与升级控制叠加运行时的能力开关automationsEnabled: env.automations.enableddashboardEnabled: env.dashboardsEnabledconnectEnabled: memberFacingMcpConnectionsEnabled(...)受env.mcpConnectionsGatingEnabled门控从组织元数据中按需透传品牌化字段存在才返回allowedDesktopVersions允许的桌面版本白名单brandAppName、brandLogoUrl、brandIconUrl、brandAccentColor自定义品牌名/Logo/图标/强调色桌面端首次启动时可用该端点一次性拉齐我的组织下能用哪些能力、必须用哪个版本、显示什么品牌避免客户端各自猜测策略。十、鉴权路径速查三种客户端如何调用 me 端点从 app.ts 的根文档路由 可以确认 Den API 支持三种调用方式用户会话Authorization: Bearer session-token适用于所有 me 端点组织 API Keyx-api-key: den_...API Key 会解析到创建它的用户及其绑定的组织成员身份因此可以调用普通用户/组织路由——但注意/v1/me/active-organization与/v1/me/orgs这类需要真实会话或组织上下文的端点有额外限制前者直接拒绝 API Key后者会按 Key 绑定的组织过滤列表公开路由健康检查与文档等无需认证。# 获取当前用户与登录方式 curl https://den-host/v1/me -H Authorization: Bearer session-token # 获取当前用户的组织列表含活跃标记 curl https://den-host/v1/me/orgs -H Authorization: Bearer session-token # 通过组织 API Key 调用按 Key 作用域过滤组织 curl https://den-host/v1/me/orgs -H x-api-key: den_... # 更新显示姓名 curl -X PATCH https://den-host/v1/me/profile \ -H Authorization: Bearer session-token \ -H Content-Type: application/json \ -d {firstName: Ada, lastName: Lovelace}十一、扩展指南如何在 me 文件夹下添加新端点遵循 README 的边界与 Den API 的既有惯例新增当前用户子域端点时应判断归属只处理调用者自己的资源我的资料、我的设备、我的会话、我的通知偏好等凡涉及操作其他用户或全局管理一律放到routes/org、routes/admin等目录。拆文件不要继续把端点堆进 index.ts按子域新建me/xxx.ts每个文件导出自己的registerXxxRoutes(app)在index.ts或 app.ts 中组合调用。选中间件只需要登录 →authenticatedRoute()requireUserMiddleware需要组织成员上下文 →orgMemberRoute({ useUserOrganizations: true })或orgMemberRoute()需要真实会话拒绝 API Key→userSessionRoute()。写 OpenAPI 描述所有端点都通过describeRoute提供tags: [Users]、summary、description与响应 Schema复用denTypeIdSchema、unauthorizedSchema、invalidRequestSchema、jsonResponse等 openapi.js 工具。校验入参请求体用jsonValidator(schema)配合 Zodtrim()与长度上限是 me 模块的一致风格。十二、总结me路由模块是 Den API 中当前用户语义的唯一入口它用最小的中间件组合requireUserMiddleware/resolveUserOrganizationsMiddleware/requireUserSessionMiddleware区分已登录、组织成员与真实会话三种信任级别在/v1/me/orgs与/v1/me/active-organization中完整实现了从组织解析 → 活跃组织判定 → 会话持久化的闭环并通过/v1/me/desktop-config把组织级策略桌面版本、能力开关、品牌定制下发给桌面端。理解这个模块是理解 Den API 面向用户侧 API 设计的起点——尤其是组织作用域解析与 single_org 模式下的收紧逻辑它们决定了多租户与单租户部署下我属于哪些组织、我当前在哪个组织这两个问题的答案。进一步阅读路由注册入口 app.ts、组织解析与活跃组织持久化 orgs.ts、鉴权中间件 current-user.ts、组织上下文中间件 user-organizations.ts、会话/API Key 鉴权测试 bearer-session.test.ts。【免费下载链接】openworkThe open-source alternative to Claude Cowork (powered by opencode)项目地址: https://gitcode.com/GitHub_Trending/ope/openwork创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门