# 全员登录可用性设计 ## 1. Boundary 本任务在现有企微 OAuth 回调内补充确定性自动绑定,不新增公开认证端点、不读取或记录任何真实密码。普通企微登录只绑定既有 active OA 账户,不创建员工、不修改角色、不写企微通讯录。 ## 1.1 WeCom Direct-login Contract ```text 企微 OAuth callback 得到内部 userid -> 已有唯一 binding:直接创建会话 -> 无 binding:读取该 userid 的企微通讯录资料 -> 企业邮箱精确匹配唯一 active OA 账户 -> 目标账户无 binding:事务内 upsert binding + 脱敏审计 + 创建会话 -> 任何缺失/无匹配/inactive/冲突/API 失败:失败关闭 ``` 匹配键优先级固定为已有 userid binding,其次为企微返回的规范化企业邮箱。姓名不得参与自动决策;手机号不作为本轮普通登录兜底,避免号码复用或格式漂移扩大身份边界。 ## 2. Login Baseline 每个 active 账户必须同时满足: 1. `WeCom SSO ready`:属于当前企微通讯录的员工存在唯一 binding,并由本人完成一次工作台直接登录;首次登录不需要 OA 密码。 2. `password fallback ready`:员工本人已设置并掌握密码;它是企微异常时的独立回退,不是首次 binding 的前置条件。 inactive/archived 账户不进入本轮登录覆盖率分母。 ## 3. Administrator Recovery ```text 受控终端 -> 精确定位唯一 active 管理员 -> 静默设置一次性密码 -> 清锁定、撤旧会话、递增 token version、失效旧验证码并留脱敏审计 电脑浏览器 -> 使用一次性密码登录 -> 立即设置本人新密码 手机企微工作台 -> 重新进入并完成 OAuth userid 校验 -> 新版 OAuth 回调用 userid 或企微企业邮箱精确匹配既有 active OA 账户 -> 自动建立唯一 binding 并直接创建会话 -> 再次从工作台进入并验证免登 ``` 一次性密码只允许由用户在受控终端静默输入,或写入仓库外权限为 `0600` 的临时文件供用户本机读取一次;不得出现在聊天、argv、环境变量、日志或仓库。它只用于管理员账号恢复,不参与企微首次 binding。 若自动匹配缺失或冲突,停止操作并只读核对 userid、企业邮箱和 OA active 账户的唯一映射;不得按姓名猜测、不得用密码登录覆盖 binding。个人设置主动绑定只保留为管理员核实后的显式维护入口。 ## 4. Remaining Active Accounts 其余 active 账户已有 binding,但尚无真实登录证据。每名员工先直接从企微工作台进入,验证 binding 和免登是否可用;企微免登通过后再按优先级安排密码回退,不让密码流程阻塞主入口验收。管理员只记录 `password_login_pass`、`wecom_login_pass`、`blocked_reason` 三类脱敏结果,不收集密码、验证码或完整账号。 邮件未送达时才进入兜底:管理员通过现有 `reset-password` 接口生成一次性密码,受控现场只显示一次并当面交付;接口强制首次改密、清除锁定、撤销旧会话、使旧凭据失效并写审计。兜底写入需在实际发生前再次获得批准。 ## 5. Failure Matrix - 邮件验证码未收到:先核对投递状态和企业邮箱可用性;不反复请求导致限流。确认邮件路径不可用后才考虑管理员一次性密码。 - 企微内无法同时看登录页和邮箱:改用电脑浏览器完成忘记密码,手机只收验证码;不要为看邮件关闭正在执行 binding 的企微 WebView。 - 验证码过期/错误:由员工重新请求;不得让管理员代收或索取验证码。 - 页面显示已发送但未看到新邮件:先只读确认是否真正签发新 code、有效期、失败次数和邮件发送失败计数。新签发会使旧 code 失效;不得混用旧邮件,也不得在请求上限内连续点击重发。 - 旧验证码被拒绝:归类为“新签发使旧码失效”,证明失败发生在 `/reset-password` 成功之前;不得据此推断前端缓存或首次改密标记未清除。 - 正确验证码重设成功后仍跳到改密页:才归类为前端状态/缓存问题,并记录跳转 URL、页面和报错;不要与旧码失效混为一类。 - 点击登录页“忘记密码”只进入找回页面,不会签发验证码。只有填写企业邮箱并点击“发送验证码/重新发送验证码”才会请求签发;页面导航次数不能作为验证码请求次数。 - 账号或邮箱锁定:只读确认锁定类别和窗口;使用现有解锁接口前另行批准。 - 企微仍显示 unbound:确认是否在企微内打开、OAuth 回调是否取得内部 userid、现有 binding 是否指向另一账户;不得按姓名猜测绑定。 - binding conflict:失败关闭,保留原映射和审计,单独核实身份后再提出精确修正。 - 邮箱验证码登录成功但必须改密页面要求未知旧密码:说明员工走了 `/email-login` 路径;它不同于会清除首次改密标记的 `/reset-password`,返回忘记密码流程,不绕过旧密码校验。 ## 6. Rollback - 员工自助重设密码后旧密码和旧会话按设计失效,无需回滚到旧密码。 - 新 binding 若经本人验证仍错误,只能在精确确认原/目标映射后使用现有解绑/绑定路径恢复;不得直接删除数据库记录。 - 任一员工阻断不影响其他员工逐人完成,但全员验收保持未完成并记录缺口计数。 ## 7. Prevention 新账号从创建/导入进入 active 后,不得只以“有密码哈希/有 binding 行”宣告可用。启用完成必须包含安全凭据交付、首次改密、密码登录和企微成员本人工作台免登四项;缺一项则保持 onboarding 未完成并由管理员跟踪。 ## 8. Compatibility And Audit - 已有 binding 的 3 个账户保持原路径,不额外请求通讯录详情。 - 自动补绑定使用现有 `wecom_identity_bindings` 唯一约束,并在同一事务内二次核对 userid 与员工两侧冲突。 - 新审计动作只记录匹配方式和布尔字段,不记录完整 userid、邮箱或企微原始 payload。 - 未绑定页面不再指示员工输入密码完成正常绑定;错误只显示稳定类别,完整身份资料不得进入 URL、日志或前端状态。 - 生产回填先 dry-run 汇总唯一匹配、无匹配和冲突计数,另行批准后才 apply。