# 增量 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 `。清理 `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 `(已部分一致,统一键名与降级逻辑;清理 `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 认证章节中的相关条款,作为三端认证重构与响应契约统一的唯一权威来源,供架构师做系统方案设计与任务分解。