在碰不熟悉的代码之前,让 Claude 挖出你还不知道自己不知道的事——并告诉你如何针对每个缺口改进提示词。
我要给 Acme 新增一个 SSO 认证提供方,但我从没碰过 auth 模块。请做一次盲点扫描:找出我在代码库这一部分的未知之未知,逐条解释,并告诉我如何针对实现更好地向你发起提示。
已扫描 services/auth/(47 个文件),自 2025 年 1 月起有 214 次提交涉及该模块,3 个迁移进行中,2 次尝试被回滚。以下是七件你本会以惨痛方式才学到的事。
「新增一个 SSO 提供方」——听起来像是:实现接口、注册、写重定向处理器,完事。在干净的代码库里,两天就能搞定。
一个会话存储正处在迁移中途的模块,有一个提供方悄悄绕过了大家都以为会跑的中介件,此前针对同一任务的尝试已被回滚,还有一个从提供方接口根本看不出来的身份关联模型。
Acme 正从 Postgres 会话迁移到 Redis(MIG-118,自三月起停滞)。每次会话写入目前都经 SessionBridge.write(),同时扇出到 RedisSessionStore 和旧版 pg_sessions 表。迁移从未完成,因此读取仍来自 Postgres。
RedisSessionStore——它看起来像标准实现,代码最新、文档最好。直接往它写,开发环境登录看似正常(那里启用了 Redis 读取),生产环境却会静默失败,因为读取仍走 Postgres。除 SAML 外,所有提供方都挂在 authPipeline 下,它会跑限流、审计日志和设备信任检查。saml/handler.ts 把 ACS 端点直接挂到路由器上,因为 2024 年 SP 发起的 POST 回调弄坏了 CSRF 层,之后没人回头处理。有一条 14 个月前的 // TODO(priya): fold back into pipeline。
PR #2841(「Add Okta OIDC provider」,2025 年 9 月)曾合并,九天后被回滚。回滚提交说明了原因:Acme 回调 URL 必须带租户后缀(/auth/callback/:provider/:workspaceSlug),这样工作区范围的邀请链接才能在重定向往返中保留。Okta 严格的 redirect-URI 匹配拒绝了动态后缀,被邀请用户落进了错误的工作区。大家在回滚讨论里达成一致的修复方案——用 AUTH_STATE_SECRET 签名的 state 参数工作区声明——设计了但从未实现。
Acme 把 users 和 identities 分开:一个账户可以关联多个身份(邮箱+密码、Google、SAML),在 identities 表里联结。提供方接口只返回 profile;关联决策发生在 identity/linker.ts,以已验证邮箱为键。无法保证已验证邮箱的提供方(许多 SSO IdP 做不到)必须设置 requiresManualLink: true,否则 linker 会把共享企业别名的两个不同人愉快地合并到一起。
刷新令牌轮换由 flags.yaml 里的 auth.refresh_rotation 控制。开发/预发默认 true,生产默认 false(五月时钟偏移事故后暂停 rollout)。开关关闭时,生产会话恰好活 ACCESS_TOKEN_TTL(12 小时)然后硬过期——没有刷新路径。
提供方能编译并不等于上线。必须 (1) 在 providers/registry.ts 注册,(2) 通过迁移写入 auth_providers 表——管理 UI 读的是数据库,不是 registry——以及 (3) 加入 __tests__/provider-contract.spec.ts 的 fixture 列表,该套件会对每个已注册提供方跑共享契约(state 校验、重放防护、登出扇出)。registry 与 fixture 列表不一致时 CI 会失败。
会话撤销会在内部事件总线上发布 auth.session.revoked。实时 review player 持有自己的长期播放授权,只有消费该事件时才会释放。logout.ts 为现有提供方处理了这件事,但 SSO 单点登出(SLO)回调走另一条路径,必须自行发布该事件。
给 Acme 新增一个 SSO 认证提供方。来自盲点扫描的约束: 1. 会话:所有会话写入经 SessionBridge(MIG-118 未完成;生产仍从 pg_sessions 读)。绝不直接碰 RedisSessionStore。 2. 模板:结构以 oauth/google.ts 为准,不要用 saml/handler.ts——SAML 绕过 authPipeline。所有新路由挂载在 authPipeline 内,并给我看挂载点。 3. 历史:先读 PR #2841 的回滚。实现带签名的 state 参数工作区声明(AUTH_STATE_SECRET),不用租户后缀回调 URL;测试工作区邀请流程。 4. 身份关联:编码前带我过 identity/linker.ts。若 IdP 不保证已验证邮箱,设 requiresManualLink 并建确认路径——勿自动关联。 5. 特性开关:按 auth.refresh_rotation=false(生产)实现。会话 12h 硬过期;无刷新路径。另注轮换上线后会变什么。 6. 注册:三步全做——providers/registry.ts、auth_providers 迁移、provider-contract fixture 列表。契约套件全绿。 7. 登出:每条撤销路径须发布 auth.session.revoked;加测试断言 IdP 发起登出时 review player 播放授权被释放。 按此顺序:linker 走读 → 提供方骨架 → 回调 + state 声明 → 注册 → SLO + 事件 → 契约测试。走读结束后先停,给我看计划再写代码。
七句话,今早你还写不出来——每一条都是用别人半天的代价换来的。这就是盲点扫描的意义。