Files
wecom_it_smart_desk/docs/02-产品需求/04-增量PRD-三端认证重构.md

168 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 增量 PRD — 三端认证重构(合并唯一认证方式 + 响应契约统一)
> **文档版本**: v1.0(增量)
> **创建日期**: 2026-07-06
> **产品经理**: 许清楚 (Xu)
> **状态**: 待架构师系统方案设计 / 任务分解
> **关联文档**:
> - `docs/02-产品需求/02-产品需求文档PRD-v1.2-20260704.md` §4.5
> - `docs/11-历史归档/PRD-admin-v1.0-archived-20260703.md` §4.4
> - 架构文档 §6.7 `/api/agents/otp-*`**本增量 PRD 裁定作废**
> - `backend/app/utils/response.py`(统一信封 `success_response` / `error_response`
---
## 0. 文档目标
1. **合并唯一认证方式**:将 PRD v1.2 §4.5 与 管理端 PRD v1.0 的认证章节合并为**唯一、无矛盾的认证规范**,消除两文档之间及文档内部的历史矛盾(统一入口残留、免密分支、登录方式数量、OTP 接口路径、员工端是否含密/OTP、管理端网络约束等)。
2. **收口响应契约统一(方案 A**:将三端 Axios 拦截器与后端统一信封**收口为同一契约**,消除 H5 返回 envelope、agent/admin 返回 AxiosResponse 的不一致。
3. 本增量 PRD 与 §4.5 是**取代关系**:凡本文件与 v1.2 §4.5 / 管理端 PRD v1.0 认证章节冲突处,**一律以本文件为准**;相关旧条款视为作废。
---
## 1. 矛盾消解对照表(核心:证明"唯一认证方式")
| # | 矛盾点 | 旧文档表述(冲突来源) | 本增量 PRD 裁定(唯一方式) |
|---|--------|------------------------|------------------------------|
| C1 | 统一入口 `/itportal/` | v1.2 §4.5.2「/itportal/ 已配置未使用,保留接口」;§4.5.7「Portal 前端 /api/portal/* 保留接口」 | **彻底移除** `/itportal/` 入口与 `/api/portal/*`;三端独立入口 `/itdesk/` `/itagent/` `/itadmin/`(决策1 |
| C2 | 管理端「免密直接进入」分支 | v1.2 §4.5.2 管理后台「企微已登录且有管理员角色 → 免密直接进入」;§4.5.4 场景一「免密直接进入」;§4.5.5「企微免密登录(wx.agentConfig)」 | **全部移除**免密分支与企微 JS-SDK 免密登录(决策4) |
| C3 | 登录方式数量 | v1.2 §4.5.3/§4.5.4「智能检测 + 三种登录方式(含免密)」 | 坐席/管理端**仅两种并列**:①企微扫码登录 ②账号密码+OTP(决策3) |
| C4 | OTP 接口路径 | v1.2 §4.5.7 `/api/mfa/*`、§4.5.10 `/api/mfa/bind/start``/api/mfa/verify`;架构 §6.7 `/api/agents/otp-*` | **统一为** `/api/auth/otp-bind` `/otp-verify` `/otp-unbind` `/otp-status`;旧路径全部作废(决策5 |
| C5 | 员工端是否含密码/OTP | v1.2 §4.5.3 仅「OAuth2 静默授权」,未禁止密码/OTP、未明确禁止企微外打开 | 员工端**无密码、无 OTP**;仅企微工作台内嵌(snsapi_base)打开;禁止企微外打开(非 wxwork UA 跳拦截页);Token 经 `?token=` 传入并镜像本地(决策2 |
| C6 | 管理端网络约束 | v1.2 与管理端 PRD v1.0 均未规定 IP 白名单/内网/VPN | **新增** 管理端仅限内网/VPN + IP 白名单:`117.147.35.138``218.75.34.87``10.240.0.0`(内网/VPN 网段)(决策6 |
| C7 | 响应拦截器不一致 | H5 成功返回 `response.data`envelope);agent/admin 成功返回 `response`AxiosResponse),调用方取 `.data.data` | 三端**统一方案 A**:成功返回内层 `data`,失败抛 `{code, message}`(决策7 |
| C8 | `portal_token` 遗留 | agent 拦截器 `handleAuthExpired` 仍清理 `portal_token` | 随 C1 清理所有 `portal_token` 引用(保留 `agent_token` |
---
## 2. 用户故事
| ID | 角色 | 用户故事 | 优先级 |
|----|------|----------|--------|
| US-EMP-1 | 普通员工 (user) | 作为普通员工,我希望在企微工作台点击应用即**直接进入** IT 服务台(无需账号密码、无 OTP),以便快速提交 IT 问题并查看进度 | P0 |
| US-EMP-2 | 普通员工 (user) | 作为普通员工,我希望在**非企微环境**打开链接时被拦截提示,避免认证异常或信息泄露 | P0 |
| US-AGT-1 | IT 坐席 (agent) | 作为 IT 坐席,我希望在浏览器打开坐席工作台时,能用**企微扫码**或**账号密码+OTP** 登录(两种方式任选),以便在任何环境进入工作台 | P0 |
| US-AGT-2 | IT 坐席 (agent) | 作为 IT 坐席,我希望 **OTP 输入框在账号密码验证通过后才出现**,避免提前暴露与误填 | P0 |
| US-ADM-1 | 管理员 (admin) | 作为管理员(组长),我希望管理后台仅能从**内网/VPN 且 IP 在白名单**内打开,并支持扫码/账号密码+OTP 登录,确保安全 | P0 |
| US-ADM-2 | 管理员 (admin) | 作为管理员,我希望管理后台与坐席端使用**相同的认证与 Token 机制**,降低维护与排查成本 | P0 |
| US-DEV-1 | 开发者 | 作为开发者,我希望本地/测试环境**跳过** UA 校验、IP 白名单与真实企微 OAuth,员工端可走 dev/mock 登录,以便不依赖企微即可联调 | P0 |
---
## 3. 需求池
> 标注规则:**AUTH-** = 认证类;**CTRT-** = 响应契约类。
> 优先级:P0=Must / P1=Should / P2=Nice-to-have。
### 3.1 认证类(AUTH
#### P0
| ID | 需求 | 说明 / 验收标准 |
|----|------|-----------------|
| AUTH-P0-1 | 三端独立入口确立 | 入口:`/itdesk/`H5,企微内嵌)、`/itagent/`(浏览器)、`/itadmin/`(浏览器)。**移除** `/itportal/` 入口与 `/api/portal/*` 保留接口(含前端 portal 工程与 `portal_token` 清理,见 C1/C8)。 |
| AUTH-P0-2 | 员工端唯一认证 | OAuth2 静默授权(snsapi_base)→ 直进工作台;**无密码、无 OTP**Token 经 URL `?token=` 传入并镜像 `localStorage`(`h5_token`)**非 wxwork UA 跳拦截页**(仅生产启用,见 AUTH-P0-7)。 |
| AUTH-P0-3 | 坐席/管理端两方式并列 | 同源认证,浏览器直开,**仅两种并列**:①企微扫码登录 ②账号密码+OTP。**移除**「企微已登录且具角色→免密直接进入」分支(C2/C3)。 |
| AUTH-P0-4 | OTP 输入框渲染时机 | OTP 输入框**默认隐藏**,仅「账号密码验证通过」后才渲染(前端修正,含原型修正,见 §4)。 |
| AUTH-P0-5 | OTP 接口统一 | 统一为 `/api/auth/otp-bind` / `otp-verify` / `otp-unbind` / `otp-status`**作废** `/api/mfa/*``/api/agents/otp-*`(C4)。语义:bind=首次绑定返回 secret/二维码;verify=校验/登录;unbind=解绑;status=查询绑定状态。 |
| AUTH-P0-6 | 管理端 IP 白名单 | 管理端仅允许 内网/VPN + IP 白名单:`117.147.35.138``218.75.34.87``10.240.0.0`(内网/VPN 网段)。非白名单 IP 拒绝访问(HTTP 403 / 拦截页)。仅生产启用(见 AUTH-P0-7)。 |
| AUTH-P0-7 | env-gating(环境门控) | UA 校验、IP 白名单、真实企微 OAuth **三者仅生产环境启用**;本地/测试环境跳过(详见 §5)。 |
| AUTH-P0-8 | 员工端本地 dev/mock 登录 | 本地/测试(ENV=dev 且未配 CorpId)走 dev/mock:复用 `backend/app/api/dev_auth.py``/api/dev/login` 签发测试 employee token`login_source="dev"`);H5 复用 `VITE_WECOM_CORP_ID` 为空时的 Mock 登录页分支。 |
| AUTH-P0-9 | Token 机制统一 | 三端统一 Bearer Token:员工端经 `?token=` 传入+本地镜像;坐席/管理端存 `localStorage``agent_token` / `admin_token`)。请求头统一 `Authorization: Bearer <token>`。清理 `portal_token` 遗留引用。 |
#### P1
| ID | 需求 | 说明 / 验收标准 |
|----|------|-----------------|
| AUTH-P1-1 | OTP 本地测试支持 | 坐席/管理端本地可直测:OTP 用标准 TOTP;本地显示 secret 或提供 dev 端点返回当前 TOTP 码。IP 白名单本地关闭。 |
| AUTH-P1-2 | 真实 OAuth 验证环境 | 真实企微 OAuth 端到端验证**仅在正式/Staging**`itsupport.servyou.com.cn`,已配企微可信域名)进行,本地不依赖。 |
| AUTH-P1-3 | 首次绑定 OTP 引导 | 首次登录引导绑定 OTP(bind→展示 secret/二维码→verify 闭环);后续登录走 verify。 |
#### P2
| ID | 需求 | 说明 / 验收标准 |
|----|------|-----------------|
| AUTH-P2-1 | 跨主体(互联企业)认证扩展 | 后续阶段支持跨主体员工:复用扫码/OTP 路径,不引入新认证方式。 |
### 3.2 响应契约类(CTRT
#### P0
| ID | 需求 | 说明 / 验收标准 |
|----|------|-----------------|
| CTRT-P0-1 | 三端拦截器统一(方案 A) | 三端 Axios **响应拦截器**统一为:成功返回**内层 `data`**`res.data`),失败抛出**标准化错误对象 `{code, message}`**。消除 H5 返回 envelope vs agent/admin 返回 AxiosResponse 的不一致(C7)。各端 401/1002 重授权逻辑保留(见 CTRT-P0-3)。 |
| CTRT-P0-2 | 三端调用点改造 | 三端现有 API 封装需适配:H5 原取 `response.data`(envelope)→ 改为直接消费内层 `data`agent/admin 原取 `response.data.data` → 改为直接消费内层 `data`(拦截器已解包)。全量回归三端 API 调用点。 |
#### P1
| ID | 需求 | 说明 / 验收标准 |
|----|------|-----------------|
| CTRT-P1-1 | 后端信封审计 | 审查全部路由,确认均经 `success_response` / `error_response` 或全局 `AppException` 处理器(`response.py`),无裸 `dict` 直返 / 漏用信封的接口;发现漏网接口整改为统一信封。 |
| CTRT-P1-2 | 请求拦截器统一 | 三端请求拦截器统一注入 `Authorization: Bearer <token>`(已部分一致,统一键名与降级逻辑;清理 `X-Employee-Id` 明文头遗留)。 |
#### 401 / 未授权 处理约定(各端保留,统一上报形态)
| 端 | 触发 | 处理(保留既有逻辑) | 上报形态 |
|----|------|----------------------|----------|
| H5 | biz1002 / http401 / UA 拦截 | 清除 `h5_token`;生产→重走 OAuth2 重定向(带防循环计数);Mock→跳 `/itdesk/login` | 抛 `{code:1002, message:"未授权"}` |
| Agent | biz1002 / http401 | 先静默刷新(`/api/auth/refresh`);失败则清除 `agent_token` 并跳 `/login` | 抛 `{code, message}` |
| Admin | biz1002 / http401 | 清除 `admin_token` 并跳 `/login` | 抛 `{code, message}` |
---
## 4. UI 设计稿说明
> 原型图目录:`docs/04-原型设计/prototypes-原型图/`
| 端 | 引用原型 | 说明 |
|----|----------|------|
| 坐席 | `agent-login-v1.html` | 登录页(企微扫码 / 账号密码+OTP 两方式并列) |
| 管理 | `admin-login-v1.html` | 管理后台登录页(与坐席同构,叠加 IP 白名单约束) |
| 员工 | `h5-user-wecom-style-v2-mobile.html` | 企微工作台内嵌 H5 样式(无独立登录页;非企微打开跳拦截页) |
### ⚠️ 重点修正(必须落到前端实现)
1. **OTP 输入框默认隐藏**`agent-login-v1.html``admin-login-v1.html` 中,OTP 输入行**初始不渲染**(或 `display:none`);仅在「账号密码验证通过」后由前端动态渲染/启用。原型原稿若存在常显 OTP 框,需按此修正。
2. **两方式并列、无免密入口**:登录页仅保留「企微扫码登录」「账号密码+OTP」两个入口;**移除**原稿中「企微免密登录」按钮与「智能检测后免密进入」分支(对应 C2/C3)。
3. **员工端无登录表单**`h5-user-wecom-style-v2-mobile.html` 不含账号密码/OTP 表单;非 wxwork UA 打开时展示拦截提示页(非登录页)。
4. **管理端网络提示**`admin-login-v1.html` 在 IP 非白名单/非内网时展示「无访问权限」拦截页(由后端 403 驱动)。
---
## 5. 测试策略
### 5.1 本地环境处理(env-gating
snsapi_base 的 `redirect_uri` 必须是企微后台配置的可信域名(`itsupport.servyou.com.cn`),本地 `localhost` 无法回调;且「禁止企微外打开」的 UA 校验在非 wxwork 浏览器会拦截。处理方案:
| 控制项 | 生产(production / itsupport.servyou.com.cn | 本地 / 测试(dev / 未配 CorpId |
|--------|-----------------------------------------------|----------------------------------|
| UA 校验(非 wxwork 跳拦截页) | **启用** | 跳过 |
| IP 白名单(管理端) | **启用** | 关闭 |
| 真实企微 OAuth | **启用** | 跳过(走 dev/mock |
### 5.2 各端验证路径
- **员工端(本地)**`VITE_WECOM_CORP_ID` 为空 → H5 走 Mock 登录页;调用 `/api/dev/login?role=user` 签发测试 employee token`login_source="dev"`),模拟 `?token=` 入参并镜像 `h5_token`,断言工作台加载。
- **员工端(真实 OAuth**:仅正式/Staging 验证 snsapi_base 静默授权 → `?token=` 传入 → 直进工作台;非 wxwork UA 验证跳拦截页。
- **坐席/管理端(本地)**:浏览器直开;OTP 用标准 TOTP(本地显示 secret 或 dev 端点返回当前码);IP 白名单本地关闭;验证两方式并列与 OTP 输入框延迟渲染。
- **管理端(生产)**:仅限内网/VPN + 白名单 IP;非白名单 403。
### 5.3 自动化测试断言(针对 dev/mock,不依赖真实企微)
1. dev/mock 登录返回 `code:0``data.token` 为合法 Bearer Token。
2. 携带 `?token=` / `Authorization: Bearer` 后,工作台/管理页可加载(API 返回内层 `data`)。
3. 注入失效 Token → 触发 401/1002 → 按端重授权(员工重 OAuth/Mock 登录页;坐席刷新后跳 /login;管理跳 /login)。
4. 拦截器统一契约:成功返回内层 `data`;失败 `catch``{code, message}`(三端一致)。
5. OTP 接口:bind 返回 secret、verify 通过/失败分支、status 查询、unbind 闭环。
---
## 6. 待确认问题
**无。** 所有认证方式、网络约束、OTP 接口、响应契约与本地测试策略均依据已确认决策(决策1–7)与现行代码(`response.py`、三端 `api/index.ts``dev_auth.py`)落定,无需进一步确认。
---
> **文档结束** — 本增量 PRD 取代 PRD v1.2 §4.5 与管理端 PRD v1.0 认证章节中的相关条款,作为三端认证重构与响应契约统一的唯一权威来源,供架构师做系统方案设计与任务分解。