hl-api-changelog/changelogs/2026-05/22_feat_sms_login_customizer_only.md

4.2 KiB

feat(user): SMS 登录限定制师 + active role 自动切 CUSTOMIZER

仓库: HL (后端 hl-user-service) 关联 PR/Issue: PR #2920, Closes #2918 日期: 2026-05-22 影响范围: 管理端 POST /admin/auth/sms/login SMS 验证码登录入口 接收方: mmg (前端) 前端: 登录页前端无 API 改动, 但 SMS 登录成功后 data.role 一定是 CUSTOMIZER (即使该 admin 还有其他角色)


🚨 关键变化

SMS 验证码登录入口 (POST /admin/auth/sms/login) 现在只允许有 CUSTOMIZER 角色的 admin 登录, 且登录成功后强制以定制师视角颁发 token (即使 admin 还有 ADMIN/OPERATOR 等其他角色)。

业务原因: SMS 登录场景仅定制师小程序分享需要 (#2907), 其他角色不应该用 SMS 绕过 2FA 登入后台。


一、API 影响

POST /admin/auth/sms/login 行为变化

场景 之前 现在
仅 CUSTOMIZER 角色 admin 用对码登录 颁发 token, role = admin.currentRoleId 对应的 roleKey 颁发 token, role 强制 = CUSTOMIZER
多角色 admin (如 CUSTOMIZER+ADMIN) 用对码登录 颁发 token, role = admin.currentRoleId 对应的 roleKey 颁发 token, role 强制 = CUSTOMIZER (无视 currentRoleId)
无 CUSTOMIZER 角色 admin 用对码登录 颁发 token, role = 当前 active role 返 200102 INVALID 验证码错误,剩余 N 次尝试 + fail+1 (防枚举)
mobile 不绑 admin 用对码登录 200102 INVALID (现有防枚举路径) 200102 INVALID (无变化)

防枚举设计

"无 CUSTOMIZER 角色 admin" 路径返回的 code/message 跟 "mobile 不绑 admin" 路径完全一致 (200102 INVALID + remainingAttempts),攻击者无法区分这两种情况, 也无法用 SMS 入口枚举哪些 mobile 是非定制师 admin。

fail count 也会累加, 错 5 次仍触发 ADMIN_SMS_CODE_VERIFY_LOCKED 15 分钟锁定 (复用 #2889 锁定机制)。

active role 强制 CUSTOMIZER 后

  • 颁发的 access token 内嵌的 role 字段 = CUSTOMIZER
  • 后续基于 token 的 @PreAuthorize("hasRole('CUSTOMIZER')") 等权限校验都按定制师视角
  • 不污染 admin.currentRoleId 持久化: SMS 是临时切角色, 不影响下次密码登录时的默认角色

🚨 前端需要做的事

1. 登录后角色显示

SMS 登录成功后 data.role 一定是 CUSTOMIZER, 顶部用户信息组件 / 角色 badge 应该按定制师展示。

不需要前端额外区分 SMS 登录 vs 账密登录: 后端已经把 role 强制设为 CUSTOMIZER, 前端按响应字段渲染即可。

2. 多角色切换

如果未来前端有"切换角色"功能 (PUT /admin/auth/role), SMS 登录拿到的 CUSTOMIZER token, 切到其他角色行为等同于密码登录路径 (后端按现有逻辑处理)。

3. 错码无新增

200102 错码已经存在, 前端无需新增映射。200107 是后端审计码不会返前端, 前端忽略。

4. 自查

grep -rE "/admin/auth/sms/login|role.*CUSTOMIZER" hl-ui/src

确认登录后 role 字段处理逻辑能正确显示 CUSTOMIZER。


二、新错码 (后端审计用, 不返前端)

code 含义
200107 ADMIN_SMS_LOGIN_NOT_CUSTOMIZER 短信验证码登录仅限定制师 (仅服务端 log.warn 审计, 防枚举不返前端)

三、测试服验证记录

部署到测试服 api.test.1814.love:9443 后真测 (2026-05-22 19:05):

# 场景 实测
T1 仅 CUSTOMIZER admin 登录 role=CUSTOMIZER + roleName=定制师 + token + requireTwoFa=False
T2 仅 ADMIN admin (无 CUSTOMIZER) 登录 200102 INVALID + remainingAttempts=4 (防枚举)
T3 多角色 admin (ADMIN+CUSTOMIZER, currentRoleId=ADMIN) 强制返 role=CUSTOMIZER, DB current_role_id=2 保持不污染

四、不在本期范围

  • 账号密码登录路径 /admin/auth/login 行为完全不动 (仍按 admin.currentRoleId)
  • 让非定制师能用 SMS 登录 (明确仅定制师)
  • 持久化改 admin.currentRoleId (SMS 是临时切角色)

五、联系人

后端: wx (呼籁旅行) 前端: mmg

如有疑问可在 #2918 评论区留言。