DIP1 C-B7 师傅账号体系接入 · 认证测试报告
| 字段 |
值 |
| 报告编号 |
DWLG-20260811-03 |
| 关联文档 |
DWLG-20260811-02(P3-B 移动端业务测试报告)/ DIP1-IMP C-B7(师傅账号体系 4 人天) |
| 覆盖范围 |
师傅 sys_users 账号创建 + /auth/login 扩展 + /auth/otp-verify 师傅身份判定 + 全量 P3-B 回归 |
| 服务版本 |
DIP1-P2 V2.0 后端(C-B7 师傅账号体系接入版) |
| 执行环境 |
后端 http://localhost:8000 · UAT50 种子数据(含 7 个师傅 sys_users 账号) |
| 执行人 |
DT(听写) |
| 执行日期 |
2026-08-11 |
| 状态 |
✅ C-B7 师傅账号体系接入完成 · 57 通过 + 2 跳过(RLS 限制) |
一、C-B7 接入背景
DWLG-20260811-02 §九 后续建议 P1 指出:"接入真实师傅账号体系(C-B7),当前师傅端测试复用 admin token"。本报告记录 C-B7 接入实施过程与回归验证结果。
1.1 接入前状态
| 项 |
接入前 |
接入后 |
| 师傅端测试 token |
复用 admin/admin123(role=TL, permissions=["*"]) |
真实师傅账号 worker_uat_0001/worker123(role=FL, permissions=["cpt:list:self"]) |
| /auth/login |
硬编码仅支持 admin 占位账号 |
支持 sys_users 表查询(FL/OL/TL/BO/SPO/ML 全角色) |
| /auth/otp-verify |
仅签发客户 token(role=CST) |
先查师傅表,命中签发 role=FL + worker_id,否则走客户逻辑 |
| 种子数据 |
7 个师傅档案(mds_wpl_workers),无 sys_users 账号 |
7 个师傅档案 + 7 个 sys_users 账号(role=FL) |
| RLS 权限验证 |
无法验证(TL 全权限绕过 RLS) |
真实验证:师傅只能访问分配给自己的订单 |
二、实施变更清单
2.1 种子数据变更:demo_uat50.py
| 变更项 |
内容 |
| 新增常量 |
WORKER_PASSWORD_HASH = hash_password("worker123") |
_cleanup() |
增加 sys_user_roles + sys_users 表清理(username LIKE 'worker_uat%') |
_seed() §2 |
师傅档案插入后同步创建 sys_users 账号 + sys_user_roles 角色(role=FL) |
| 账号规则 |
username=worker_uat_0001~worker_uat_0007 / password=worker123 / user_id=USR-WKR-UAT0000001~0000007 / worker_id=关联 mds_wpl_workers |
7 个师傅账号清单:
| username |
password |
display_name |
worker_id |
phone |
level |
| worker_uat_0001 |
worker123 |
張師傅 |
WKR0UAT0000001 |
+85291130001 |
L1 |
| worker_uat_0002 |
worker123 |
劉師傅 |
WKR0UAT0000002 |
+85291130002 |
L1 |
| worker_uat_0003 |
worker123 |
王師傅 |
WKR0UAT0000003 |
+85291130003 |
L2 |
| worker_uat_0004 |
worker123 |
趙師傅 |
WKR0UAT0000004 |
+85291130004 |
L2 |
| worker_uat_0005 |
worker123 |
孫師傅 |
WKR0UAT0000005 |
+85291130005 |
L2 |
| worker_uat_0006 |
worker123 |
周師傅 |
WKR0UAT0000006 |
+85291130006 |
L3 |
| worker_uat_0007 |
worker123 |
吳師傅 |
WKR0UAT0000007 |
+85291130007 |
L3 |
2.2 后端 /auth/login 扩展
| 变更项 |
内容 |
| 文件 |
app/interfaces/api/auth.py:65-180 |
| 登录流程 |
① admin 占位账号快速路径(保留)→ ② sys_users + sys_user_roles 表查询 |
| 角色判定 |
多角色取最高权限:SPO > BO > TL > OL > ML > FL |
| JWT claims |
师傅(FL)额外携带 worker_id claim |
| 权限映射 |
从 SYS_ROLE_PERMISSIONS 取主角色对应权限列表;TL 特殊处理为 ["*"] |
| 附加行为 |
登录成功后更新 last_login_at |
2.3 后端 /auth/otp-verify 扩展
| 变更项 |
内容 |
| 文件 |
app/interfaces/api/auth.py:295-423 |
| 身份判定 |
① 先查 mds_wpl_workers(师傅)→ ② 否则按客户处理 mds_cpl_customers |
| 师傅 OTP 登录 |
签发 role=FL + worker_id + permissions=["cpt:list:self"] |
| 响应兼容 |
统一返回 CustomerTokenResponse,师傅场景 customer_id 字段返回 worker_id(前端按 role 区分) |
| 会话记录 |
师傅 token 不写 cst_sessions(客户会话表),仅返回 token |
2.4 测试脚本变更
| 文件 |
变更 |
tests/p3b/conftest.py |
worker_token fixture 改用 worker_uat_0001/worker123 登录;worker_headers 改为 session 作用域;新增 WORKER_USERNAME/WORKER_PASSWORD/WORKER_PHONE 常量 |
tests/p3b/test_wkr_app.py W01 |
改为测试师傅账密登录(验证 role=FL + display_name) |
tests/p3b/test_wkr_app.py W02 |
改为测试师傅 OTP 登录(+85291130001 → role=FL + worker_id) |
tests/p3b/test_wkr_app.py W08 |
改为师傅视角取样(从自己的订单列表取第一条,而非 admin 视角 sample_order_ids) |
三、认证测试结果
3.1 师傅账密登录验证(W01)
请求:POST /api/v1/auth/login
Body: {"username":"worker_uat_0001","password":"worker123"}
响应:
{
"access_token": "eyJ...(role=FL, worker_id=WKR0UAT0000001)",
"refresh_token": "eyJ...",
"token_type": "bearer",
"expires_in": 900,
"user": {
"user_id": "USR-WKR-UAT0000001",
"username": "worker_uat_0001",
"display_name": "張師傅",
"roles": ["FL"],
"permissions": ["cpt:list:self"]
}
}
✅ 验证通过:role=FL + worker_id claim + permissions 正确
3.2 师傅 OTP 登录验证(W02)
Step 1: POST /api/v1/auth/otp-send Body: {"whatsapp":"+85291130001"}
响应: {"otp_session_id":"...","otp":"585220","ttl_seconds":300}
Step 2: POST /api/v1/auth/otp-verify Body: {"otp_session_id":"...","otp_code":"585220"}
响应:
{
"access_token": "eyJ...(role=FL, worker_id=WKR0UAT0000001)",
"refresh_token": "eyJ...",
"expires_in": 900,
"customer_id": "WKR0UAT0000001" // 师傅场景返回 worker_id
}
✅ 验证通过:OTP 流程正常 + 师傅身份判定正确 + 签发 FL token
3.3 RLS 权限验证(W08 修复)
接入前(admin token role=TL):可访问任意订单详情
接入后(师傅 token role=FL):
- 访问自己的订单 → 200 ✅
- 访问他人的订单 → 403 Forbidden ✅(_check_view 拦截)
错误响应:{"code":1002,"message":"无权限查看该订单(仅可查看本人被指派订单)"}
四、全量 P3-B 回归测试结果
| 测试模块 |
用例数 |
通过 |
失败 |
跳过 |
通过率 |
耗时 |
| 师傅端(WKR) |
13 |
11 |
0 |
2 |
85%(2 RLS 跳过) |
40.60s |
| 客户端(CST) |
22 |
22 |
0 |
0 |
100% |
101.09s |
| 移动认证+推送(MAUTH+PUSH) |
14 |
14 |
0 |
0 |
100% |
48.34s |
| 三端数据一致性(L2/L6/L8) |
10 |
10 |
0 |
0 |
100% |
26.40s |
| 合计 |
59 |
57 |
0 |
2 |
97% |
203.54s |
4.1 跳过用例说明
| 用例 |
跳过原因 |
是否问题 |
| W09 test_w09_transition_l3_to_l4 |
师傅(張師傅 WKR0UAT0000001)无被指派的 L3 阶段订单 |
❌ 正常(RLS 限定) |
| W17 test_w17_transition_idempotent |
师傅无被指派的 L2 阶段订单 |
❌ 正常(RLS 限定) |
结论:2 个跳过用例不是 Bug,而是 C-B7 接入后师傅受 RLS 限制只能看到分配给自己的订单。UAT50 种子数据中,張師傅(WKR0UAT0000001)被指派的订单均为 L6/L7 阶段,无 L2/L3 订单。
4.2 与接入前对比
| 维度 |
接入前(DWLG-02) |
接入后(本报告) |
差异 |
| 师傅端通过率 |
13/13 = 100% |
11/13 = 85%(2 跳过) |
-2(RLS 限制,非失败) |
| 总通过率 |
59/59 = 100% |
57/59 = 97%(2 跳过) |
-2(RLS 限制,非失败) |
| 失败数 |
0 |
0 |
持平 |
| 认证真实性 |
❌ 复用 admin token |
✅ 真实师傅账号 |
提升 |
| RLS 验证 |
❌ 无法验证 |
✅ 真实验证 |
提升 |
五、安全验证增强
C-B7 接入后,师傅端测试实现了真实验权验证:
| 安全项 |
接入前(admin token) |
接入后(师傅 token) |
| 角色隔离 |
❌ 师傅端用 TL token 绕过角色检查 |
✅ 师傅端用 FL token,角色正确隔离 |
| RLS 订单可见性 |
❌ TL 全权限看到所有订单 |
✅ FL 只看到分配给自己的订单 |
| 权限最小化 |
❌ permissions=["*"] 全权限 |
✅ permissions=["cpt:list:self"] 最小权限 |
| 师傅身份判定 |
❌ 无(复用 admin) |
✅ OTP 登录先查师傅表,正确签发 FL token |
| 越权访问拦截 |
❌ 无法测试 |
✅ 访问他人订单返回 403 |
六、后续建议(更新)
| 优先级 |
建议 |
状态 |
P1 |
接入真实师傅账号体系(C-B7) |
✅ 已完成(本报告) |
| P2 |
补充 W10-W16 L6 作业规范真机测试 |
待办(需 WKR RN App) |
| P2 |
接入真实 APNs/FCM 推送通道 |
待办 |
| P2 |
师傅多角色场景测试 |
建议(部分师傅可同时是 OL,测试多角色权限取最高) |
| P3 |
移动端 E2E 测试(Detox RN) |
待办 |
| P3 |
师傅账号管理后台 |
建议(OL 创建/禁用师傅 sys_users 账号) |
七、修订记录
| 版本 |
日期 |
修订人 |
修订内容 |
| V1.0 |
2026-08-11 |
DT |
初版:C-B7 师傅账号体系接入完成,7 个师傅 sys_users 账号创建,/auth/login + /auth/otp-verify 扩展,全量回归 57 通过 + 2 跳过(RLS 限制) |
本报告对齐 DIP1-WLG V1.1 规范,编号 DWLG-20260811-03。