Files
wecom_it_smart_desk/docs/02-技术文档/技术方案-REQ-认证-统一认证与登录-v1.0.md
T

187 lines
9.6 KiB
Markdown
Raw Normal View History

# 技术方案-REQ-认证-统一认证与登录
> **版本**: v1.0 | **日期**: 2026-08-05 | **状态**: 预研整合(与 PRD v1.1 对齐)
> **作者**: 宋献(产品)/ 技术评审:—
> **关联文档**:
> - PRD`../01-产品文档/01-认证与登录/PRD-REQ-认证-统一认证与登录-v1.1.md`
> - 测试用例:`../03-测试文档/03-功能测试用例/TC-REQ-认证-统一认证与登录-v1.0.md`
> - OTP 运维:`部署运维/06-OTP二次验证实现.md`
> - 扫码+OTP 部署:`部署运维/07-扫码登录OTP部署指南-v0.7.0.md`
> - 管理端登录序列:`技术架构/05-架构图/admin-login-sequence.mermaid`
---
## 1. 背景与目标
本技术方案是认证与登录模块的**技术单一真源**,与 PRD v1.1、测试用例 v1.0 形成「三件套」。
目标:
1. 收敛散落在运维/测试/架构文档中的认证技术设计,统一到 `02-技术文档`
2. 明确各通道的接口契约、数据模型与认证强度约束;
3. 为 REQ-认证-003(坐席端一键免登录)提供设计预研;
4. 为 REQ-认证-004(管理端一键免登录)保留设计边界(**不立项**)。
---
## 2. 认证能力现状(技术视角)
### 2.1 扫码登录(REQ-认证-001,已上线 v0.7.0
| 项 | 内容 |
|---|---|
| 后端端点 | `/api/auth_qrcode/*`v0.7.0 新增 4 个端点) |
| 前端 | `frontend-agent/src/views/Login.vue``frontend-admin/src/views/Login.vue` 重写扫码 UI`frontend-portal/src/views/QrcodeLogin.vue` |
| 安全属性 | 双信道分离(手机认证 ≠ PC 操作)+ 人工主动扫码 = 弱 2FA / 带外确认 |
| 部署 | 见 `部署运维/07-扫码登录OTP部署指南-v0.7.0.md` |
### 2.2 账号绑定(REQ-认证-002,已上线)
- 坐席首次通过企微身份登录后,后端将其企微 `userid` 与系统 `agent` 账号建立绑定关系(写入 `agents` / 角色关联表)。
- 绑定是「一键免登录」「角色校验」「OTP 启用」的共同前置条件。
### 2.3 OTP / MFA 二次验证(已上线 v0.7.0
| 项 | 内容 |
|---|---|
| 机制 | TOTPpyotp / Google Authenticator),SMS(蜂鸟)作为备用通道 |
| 数据模型 | `users.mfa_secret``users.mfa_enabled``users.mfa_bound_at``users.mfa_last_verified_at` |
| 后端接口 | `/api/auth/otp-*`6 个端点,见 `app/api/otp.py`)、`/api/auth/otp-admin-reset/{employee_id}`(管理员重置)、`/api/admin/high-risk/*`(高危操作 OTP 守卫 `require_high_risk_otp` |
| 登录流程 | admin 角色且 `mfa_enabled=1` 时,登录返回 `require_otp: True`,前端显示 OTP 输入框,验证通过才签发 token |
| 角色差异 | 坐席 OTP **可选**(绑定后启用);admin OTP **强制常驻第二因子** |
| 错误码 | 1006/1007/1008/1009/1010OTP 相关) |
> ⚠️ **文档一致性提示(2026-08-05 更新)**`部署运维/06-OTP二次验证实现.md` 原使用 v0.5.6 旧命名 `/api/agents/otp-*`,已于 2026-08-05 修正为当前生产实现 **`/api/auth/otp-*`**(路由文件 `app/api/otp.py`prefix=`/auth`)。部署指南 `07-扫码登录OTP部署指南-v0.7.0.md`、测试用例 `TC-REQ-认证-统一认证与登录-v1.0.md` 与前端 `frontend-agent/src/api/mfa.ts` 端点调用中原引用的更早规划命名 `/api/mfa/*`,已在本轮(2026-08-05)一并修正为 `/api/auth/otp-*`AUTH-03 重构已用其取代原 `/mfa/*` 与 `/admin/mfa/*`)。当前活跃文档与实现已一致。
### 2.4 企微 JS-SDK 免登录(`jsdk-login`,现成半截)
| 项 | 内容 |
|---|---|
| 接口 | `POST /api/auth_wecom/jsdk-login` |
| 行为 | 传入企微 `userid` → 后端查角色 → 直接返回 tokenagent / admin / user |
| 现状 | 已在测试用例 JSDK-01~05 覆盖,是「一键免登录」后端的**现成半截**——缺前端在登录页主动拿 `userid` 的环节 |
| 风险点 | 历史上 `EmergencyDispatcher.vue:113` 曾用未赋值的 `window.wecom_userid` 全局变量,导致拿不到 userid;**userid 必须来自标准 SDK 调用,禁止依赖全局变量** |
### 2.5 管理端登录基础序列
`技术架构/05-架构图/admin-login-sequence.mermaid` 描述基础序列:`/api/agents/login`user_id + name)→ DB 查 role → Redis 存 token → 前端校验 `role==="admin"` → 存 `admin_token` → 跳转 `/admin/dashboard`。注意:该序列为 OTP 启用前的基础流,生产流已叠加 §2.3 的 OTP 步骤。
---
## 3. 接口契约汇总
| 通道 | 端点 | 说明 |
|---|---|---|
| 扫码登录 | `/api/auth_qrcode/*`4 端点) | v0.7.0 新增 |
| 企微免密 | `POST /api/auth_wecom/jsdk-login` | 传 userid → 返回 token |
| 账号密码 | `POST /api/agents/login` | 坐席/管理员账号密码 + OTP |
| OTP | `/api/auth/otp-*`(6 端点) | 绑定/验证/解绑等(见 `app/api/otp.py` |
| OTP 重置 | `POST /api/auth/otp-admin-reset/{employee_id}` | 管理员重置 |
| 高危守卫 | `/api/admin/high-risk/*` + `require_high_risk_otp` | 高危操作 OTP 守卫 |
| 一键(预研) | `POST /api/auth/check-wecom-bind?userid=&role=agent`(待建) | REQ-003 新增 |
**数据模型关键字段**`agents.userid`(企微绑定)、`users.mfa_secret/enabled/bound_at/last_verified_at``role`agent/admin/user)。
---
## 4. 认证强度分级技术约束(对应 PRD §3)
以「风险敞口」而非「功能对称」分配认证强度:
| 通道 | 技术约束 |
|---|---|
| 扫码登录 | 基准通道,始终保留;双信道弱 2FA |
| 一键免登录(agentConfig | **仅坐席端**;仅 PC 端、仅已绑定用户;token 有效期 < 8h(建议 24h + refresh);复用 `jsdk-login` 签发 |
| 管理端登录 | OTP 常驻强制第二因子;**不套用一键免登录** |
| 管理端一键(未来) | **不立项**;若未来立项,OTP 必须作为前置强制第二因子 |
---
## 5. REQ-认证-003 坐席端一键免登录 — 设计预研
### 5.1 总体时序
```
登录页加载
→ isWecomEnv()?(UA 含 wxwork)
否 → 走原扫码
是 → wx.config + wx.agentConfig(with_agent_config=true) 拿 userid
→ POST /api/auth/check-wecom-bind?userid=&role=agent
has_bind=true → 显示「一键登录」→ 复用 jsdk-login 签发 token → 工作台
has_bind=false → 回落扫码 + 提示语
```
### 5.2 前端断点
- 文件:`frontend-agent/src/views/Login.vue`
- 在现有 `isWecomEnv()` 分支内补齐 `wx.agentConfig` 调用链(签名复用 `wecom_jsapi.py``with_agent_config=true`,见 `wecom_jsapi.py:33`)。
- `userid` 必须来自 `wx.agentConfig` 回调,**禁止 `window.wecom_userid`**。
- UI:校验通过显示「🟢 一键登录」按钮;失败静默回落扫码。
### 5.3 后端断点
- 新增 `POST /api/auth/check-wecom-bind`(参数 `userid` + `expected_role=agent`),返回 `has_bind` + `role`
- 一键签发复用 `jsdk-login` 的 userid→token 逻辑(不新建签发路径)。
- H5 端无需改动(员工本就在企微内运行)。
### 5.4 安全约束
- 仅对**已绑定用户**开放;token 有效期短于 8h(建议 24h + refresh)。
- 失败/异常一律回落扫码,不影响存量用户。
- 不引入 `window.wecom_userid` 全局变量(历史 bug 教训)。
### 5.5 复用关系
- 复用:`isWecomEnv()`Login.vue 已有)、`wecom_jsapi.py` 签名、`jsdk-login` 签发、角色校验表。
- 新增:仅 `check-wecom-bind` 一个接口 + Login.vue 的 agentConfig 调用与 UI。
---
## 6. REQ-认证-004 管理端一键免登录 — 设计预留(不立项)
**决策(2026-08-05Q3**:**不立项**。管理端风险敞口(系统配置/权限/全局数据)远大于坐席端,按 §4 分级不套用一键免登录。
仅作未来设计边界预留(不进入排期):
- 若未来立项,必须复用 REQ-003 的企微身份探测 + 将既有 OTP(`/api/auth/otp-*`)作为**前置强制第二因子**
- 新增部分仅为「企微身份一键探测 + 复用既有 OTP 作前置网关」,非从零建设 OTP。
---
## 7. 非目标
1. REQ-003 仅预研,本次不开发;
2. 管理端一键(REQ-004)不立项;
3. 不改变扫码登录(基准通道);
4. 不新建 OTP 体系(复用既有 `/api/auth/otp-*`);
5. 不涉及 H5 登录改造。
---
## 8. 风险与缓解
| 风险 | 缓解 |
|---|---|
| 单设备被控 → 攻击者可无手机配合新发起会话 | 仅已绑定用户 + 短时效 token + 设备绑定(P2 |
| agentConfig 调用失败 | 静默回落扫码 |
| `window.wecom_userid` 未赋值 | 禁止全局变量,强制标准 SDK 调用 |
| 06 文档端点命名偏差(旧 `/api/agents/otp-*` | 已于 2026-08-05 修正为生产实现 `/api/auth/otp-*`;07 部署指南/TC 测试用例/前端 `mfa.ts` 端点调用中的 `/api/mfa/*` 规划命名亦于本轮(2026-08-05)一并修正,活跃文档与实现已一致 |
---
## 9. 关联文档索引
| 文档 | 路径 | 用途 |
|---|---|---|
| PRD | `../01-产品文档/01-认证与登录/PRD-REQ-认证-统一认证与登录-v1.1.md` | 产品需求 |
| 测试用例 | `../03-测试文档/03-功能测试用例/TC-REQ-认证-统一认证与登录-v1.0.md` | 功能用例 |
| OTP 实现 | `部署运维/06-OTP二次验证实现.md` | OTP 机制(端点命名待对齐) |
| 扫码+OTP 部署 | `部署运维/07-扫码登录OTP部署指南-v0.7.0.md` | 部署与现状 |
| admin 登录序列 | `技术架构/05-架构图/admin-login-sequence.mermaid` | 序列图 |
---
## 10. 修订历史
| 版本 | 日期 | 变更内容 | 修改人 |
|---|---|---|---|
| v1.0 | 2026-08-05 | 初始技术方案:收敛认证技术设计、接口契约、认证强度分级约束、REQ-003 设计预研、REQ-004 不立项边界 | 宋献 |