fix: restrict password login to existing phone accounts

This commit is contained in:
2026-04-26 01:11:45 +08:00
parent c4b9b8173f
commit 0a0f3f1bd8
33 changed files with 489 additions and 778 deletions

View File

@@ -18,7 +18,7 @@
当前 Node 鉴权主链已经依赖 `users` 主表完成以下能力:
1. `POST /api/auth/entry`用户名密码登录,不存在则自动创建账号
1. `POST /api/auth/entry`手机号密码登录,仅允许已存在且已设置密码的手机号账号登录
2. `POST /api/auth/phone/login`:手机号验证码登录,不存在则自动创建账号
3. `GET /api/auth/me`:读取当前账号基础信息
4. `POST /api/auth/logout`:提升 `token_version`,让当前 access token 失效
@@ -99,8 +99,9 @@
| 字段名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `user_id` | `String` | 是 | 主键,继续沿用当前 `user_*` 前缀格式。 |
| `username` | `String` | 是 | 当前密码登录用户名;手机号/微信创建的系统账号同样要写入唯一用户名。 |
| `password_hash` | `String` | | 密码登录校验字段;手机号/微信建账号时继续写随机密码哈希,保持兼容。 |
| `username` | `String` | 是 | 系统账号名;不再作为前台密码登录标识,手机号/微信创建账号时仍写入唯一系统用户名。 |
| `password_hash` | `Option<String>` | | 用户显式设置或重置密码后才写入;手机号/微信建账号默认不可用密码登录。 |
| `password_login_enabled` | `bool` | 是 | 是否允许密码登录;只有用户设置或重置密码后才为 `true`。 |
| `token_version` | `u32` | 是 | access token 统一失效计数,默认 `1`。 |
| `display_name` | `String` | 是 | 账号展示名;密码账号默认用户名,手机号账号默认脱敏手机号,微信待绑定账号默认微信昵称或“微信旅人”。 |
| `login_provider` | `String` | 是 | 当前账号的主登录归属,枚举固定为 `password``phone``wechat`。 |
@@ -131,9 +132,9 @@
### 6.2 必须具备的查询索引
1. `username`
作用:支撑 `POST /api/auth/entry`
作用:系统账号唯一约束与内部排查,不作为前台密码登录入口
2. `primary_phone_e164`
作用:支撑 `POST /api/auth/phone/login``POST /api/auth/phone/change`
作用:支撑 `POST /api/auth/entry``POST /api/auth/phone/login``POST /api/auth/phone/change`
3. `account_status + updated_at`
作用:后续管理端、审计排查与禁用账号扫描
4. `merged_to_user_id`
@@ -188,13 +189,12 @@
写入规则:
1. 先按 `username` 查询
2. 若不存在,则创建一条 `active` 账号
3. `login_provider = password`
4. `display_name = username`
5. `primary_phone_e164 = null`
6. `phone_verified_at = null`
7. `last_login_at = 当前时间`
1. 只读取请求中的 `phone``password`
2. 先把 `phone` 归一化为 `primary_phone_e164` 后查询账号
3. 若手机号不存在,返回 `401`,不创建账号。
4. 若账号存在但 `password_login_enabled = false``password_hash = null`,返回 `401`
5. 若账号存在且已设置密码,校验 `password_hash`
6. 校验成功后只更新登录会话与 `last_login_at`,不改变账号主归属。
### 8.2 `POST /api/auth/phone/login`