跳转至

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。