父节点
c51c78512d
当前提交
539fc0fc6e
@ -0,0 +1,104 @@
|
||||
# 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. 自查
|
||||
|
||||
```bash
|
||||
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](https://git.1814.love:8443/wx/HL/issues/2918) 评论区留言。
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户