Files
wecom_it_smart_desk/docs/06-测试质量/OTP绑定-测试报告-20260708.md
T
Simon e4e2de47bb docs: test reports + knowledge iteration design + PRDs
提交 OTP/RBAC/Tier0/Tier1/P0+P2 测试报告、方案A E2E 验证、知识库迭代设计(PRD/mermaid/html 原型)、项目状态看板更新; 根配置 docker-compose.yml/mkdocs.yml。
2026-07-09 11:50:19 +08:00

8.1 KiB
Raw Blame History

OTP 首次绑定与管理后台清除功能 — 测试报告

测试工程师: Edward(严过关)
测试日期: 2026-07-08
测试轮次: Round 1(发现 BUG+ Round 2(回归验证)
关联 PRD: docs/02-产品需求/05-增量PRD-OTP首次绑定与重置.md
关联设计: docs/03-技术架构/01-OTP首次绑定与重置-系统设计.md
测试文件: backend/tests/test_otp_bind_flow.py21 个测试用例)


一、测试概览

维度 Round 1 Round 2
测试用例 21 个 21 个
通过 17 个 21 个
失败 4 个(测试基础设施问题) 0 个
发现 BUG 2 个1 CRITICAL + 1 LOW 0 个(全部已修复)
现有测试回归 11 个被预期破坏 11 个(待后续更新)
前端坐席端 TS 构建 通过 通过
前端管理端 TS 构建 通过 通过

二、测试用例清单与结果(Round 2 最终)

Part A: 登录行为变更

# 用例 R1 R2 说明
A1.1 新坐席(mfa_enabled=False)登录 → require_otp_bind=true + 半认证 token BUG-001 修复后同时返回 token
A1.2 require_otp_bind 响应含引导文案 message 含"绑定"关键词
A1.3 全新坐席自动注册后也返回 require_otp_bind + token 堵死"无 OTP 直通"漏洞
A2.1 已绑定坐席无 OTP → require_otp=true(回归) 行为不变
A2.2 已绑定坐席正确 OTP → 签发 token(回归) 行为不变
A2.3 已绑定坐席错误 OTP → 报错 1006(回归) 行为不变

Part B: OTP 首次绑定验证 (verify_otp)

# 用例 R1 R2 说明
B1.1 首次绑定 + 正确 OTP → verified=true + token + is_first_bind DB 更新 mfa_enabled=True
B1.2 首次绑定 + 错误 OTP → verified=false, DB 不变 BUG-002 修复: token 字段已 exclude
B2.1 已绑定 + 正确 OTP → verified=true, 无 token(回归) BUG-002 修复: token 字段已 exclude
B2.2 无 secret 调用 verify → verified=false 边界场景处理正确
B3 首次绑定签发的 token 可用于 /agents/me 认证 token 有效性验证通过

Part C: 管理后台端点

# 用例 R1 R2 说明
C1.1 管理员查看列表含 mfa_enabled/mfa_bound_at 等字段 数据结构完整
C1.2 非 admin 访问返回 403 权限校验正确
C2.1 管理员清除绑定 → DB 清空 mfa_* 字段 secret/enabled/bound_at 均清空
C2.2 清除不存在的坐席 → 错误 错误处理正确
C2.3 非 admin 调用 reset → 403 权限校验正确

Part D: 认证缺口探查

# 用例 R1 R2 说明
D1 无 token 调用 otp-bind → 401/403 安全基线: 认证强制
D2 无 token 调用 otp-verify → 401/403 安全基线: 认证强制
D3 完整首次绑定流程无注入 R2 升级: login→otp-bind→otp-verify→token→auth 全链路通过

Part E: 端到端流程

# 用例 R1 R2 说明
E1 登录→otp-bind→otp-verify→token→认证可用 业务逻辑链路正确

Part F: Reset 后重绑

# 用例 R1 R2 说明
F1 管理员清除后坐席登录返回 require_otp_bind 重绑流程入口正确

三、发现的 BUG 及修复验证

BUG-001 [CRITICAL] — 已修复

问题: agent_loginmfa_enabled=False 返回 require_otp_bind 但不签发 token,导致前端无法调用 otp-bind/otp-verify

修复: agents.py:289-313else 分支现在通过 TokenService.create_token() 签发半认证 tokenlogin_source="agent_pending_otp"),返回响应同时含 require_otp_bind: true + token

验证: 测试 D3(原认证缺口测试)升级为完整流程验证——登录获取半认证 token → 调用 otp-bind 成功 → 调用 otp-verify 成功 → 获取完整 token → /agents/me 认证通过。

BUG-002 [LOW] — 已修复

问题: MFAVerifyResponse.model_dump() 始终序列化 token: null

修复: otp.py 3 处 model_dump() 调用均添加 exclude={"token"},非首次绑定场景的响应不再含 token 字段。

验证: 测试 B1.2、B2.1 已更新为 assert "token" not in data


四、现有测试回归影响

以下 11 个现有测试用例agent_login 行为变更被破坏,需后续更新(非本次阻塞项):

文件 用例 破坏原因
test_otp_unified.py test_new_user_status_unbound _login_and_get_token 期望 token 但收到 require_otp_bind
test_otp_unified.py test_bind_returns_secret_and_qrcode 同上
test_otp_unified.py test_admin_reset_target_user 同上
test_otp_unified.py test_admin_list_users 同上
test_agents_auth.py test_login_new_agent 等 7 个 期望 data.status/token 但收到 require_otp_bind

建议: BUG-001 修复后,_login_and_get_token 可改为从 require_otp_bind 响应中提取 token 继续流程。


五、前端 TypeScript 编译检查

Round 1 Round 2 详情
坐席端 (frontend-agent) 无变更,pnpm build 成功
管理端 (frontend-admin) 3 个预存 TS 错误在 troubleshooting.ts(与 OTP 无关)

六、全链路验证结果(Round 2 最终)

6.1 首次绑定全链路(无 token 注入)

1. POST /api/agents/login (mfa_enabled=False)
   → { require_otp_bind: true, token: "<半认证token>", user_id, name, role } ✓

2. POST /api/auth/otp-bind (Authorization: Bearer <半认证token>)
   → { secret, otpauth_url, qr_code_base64 } ✓

3. 用户扫码 + 输入 6 位 OTP 码

4. POST /api/auth/otp-verify (Authorization: Bearer <半认证token>)
   → { verified: true, is_first_bind: true, token: "<完整token>", user_id, name, role } ✓

5. GET /api/agents/me (Authorization: Bearer <完整token>)
   → { user_id, name, status } ✓

6. DB 验证: mfa_enabled=True, mfa_bound_at 已设置, mfa_last_verified_at 已设置 ✓
7. Redis: mfa:verified:{user_id} 标记已写入 ✓

6.2 已绑定用户登录链路(回归)

1. POST /api/agents/login (mfa_enabled=True, 无 otp_code)
   → { require_otp: true } ✓

2. POST /api/agents/login (mfa_enabled=True, otp_code=正确)
   → { token, user_id, name, ... } ✓

3. POST /api/agents/login (mfa_enabled=True, otp_code=错误)
   → { code: 1006, message: "OTP验证码错误" } ✓

6.3 Reset → Rebind 链路

管理员 POST /auth/otp-admin-reset/{id}
  → DB mfa_* 清空 ✓ → Redis 标记清除 ✓
  → 坐席登录 → require_otp_bind + 半认证 token ✓
  → 重新走首次绑定流程 ✓

七、路由决策

Send To: NoOne

所有 21 个测试用例通过,2 个 BUG 均已修复并验证。测试通过,无需进一步修复。

建议后续工作

  1. 更新 11 个被破坏的现有测试用例(test_otp_unified.py + test_agents_auth.py
  2. 前端坐席端 agent.ts:login() 需要适配新的 require_otp_bind + token 响应格式
  3. 前端 OtpBindPanel.vue 确保 apiClient 在调用 otp-bind/otp-verify 时携带半认证 token

八、测试文件交付

文件 路径 说明
新增测试 backend/tests/test_otp_bind_flow.py 21 个用例,覆盖 A-F 六大类场景
测试报告 docs/06-测试质量/OTP绑定-测试报告-20260708.md Round 1 + Round 2 完整记录

报告结束 — 第二轮回归测试通过。BUG-001 和 BUG-002 已修复并验证。全链路端到端流程可在无 token 注入的情况下完整运行。