14 KiB
14 KiB
增量 PRD — 三端认证重构(合并唯一认证方式 + 响应契约统一)
文档版本: v1.0(增量)
创建日期: 2026-07-06
产品经理: 许清楚 (Xu)
状态: 待架构师系统方案设计 / 任务分解
关联文档:
docs/02-产品需求/02-产品需求文档PRD-v1.2-20260704.md§4.5docs/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. 文档目标
- 合并唯一认证方式:将 PRD v1.2 §4.5 与 管理端 PRD v1.0 的认证章节合并为唯一、无矛盾的认证规范,消除两文档之间及文档内部的历史矛盾(统一入口残留、免密分支、登录方式数量、OTP 接口路径、员工端是否含密/OTP、管理端网络约束等)。
- 收口响应契约统一(方案 A):将三端 Axios 拦截器与后端统一信封收口为同一契约,消除 H5 返回 envelope、agent/admin 返回 AxiosResponse 的不一致。
- 本增量 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 样式(无独立登录页;非企微打开跳拦截页) |
⚠️ 重点修正(必须落到前端实现)
- OTP 输入框默认隐藏:
agent-login-v1.html与admin-login-v1.html中,OTP 输入行初始不渲染(或display:none);仅在「账号密码验证通过」后由前端动态渲染/启用。原型原稿若存在常显 OTP 框,需按此修正。 - 两方式并列、无免密入口:登录页仅保留「企微扫码登录」「账号密码+OTP」两个入口;移除原稿中「企微免密登录」按钮与「智能检测后免密进入」分支(对应 C2/C3)。
- 员工端无登录表单:
h5-user-wecom-style-v2-mobile.html不含账号密码/OTP 表单;非 wxwork UA 打开时展示拦截提示页(非登录页)。 - 管理端网络提示:
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,不依赖真实企微)
- dev/mock 登录返回
code:0且data.token为合法 Bearer Token。 - 携带
?token=/Authorization: Bearer后,工作台/管理页可加载(API 返回内层data)。 - 注入失效 Token → 触发 401/1002 → 按端重授权(员工重 OAuth/Mock 登录页;坐席刷新后跳 /login;管理跳 /login)。
- 拦截器统一契约:成功返回内层
data;失败catch到{code, message}(三端一致)。 - 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 认证章节中的相关条款,作为三端认证重构与响应契约统一的唯一权威来源,供架构师做系统方案设计与任务分解。