fix: restrict password login to existing phone accounts
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 密码登录历史落地设计
|
||||
# 密码登录入口历史落地设计
|
||||
|
||||
> 2026-04-24 更新:当前产品策略已调整为“不开放密码注册”。新用户必须通过手机号验证码注册/登录,密码登录只面向已经设置密码的账号。密码修改与重置以 [PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md](./PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md) 为准;本文中“密码自动建号”仅保留为历史基线说明,不再作为当前落地依据。
|
||||
> 2026-04-25 更新:当前产品策略已调整为“不开放密码注册”。新用户必须通过手机号验证码注册/登录,密码登录只面向已经登录后设置过密码的手机号账号。`POST /api/auth/entry` 只接受 `phone + password`,不支持邮箱、用户名或叙世号登录,也不承担自动建号能力。本文原有“密码自动建号”内容仅作为历史背景保留,当前落地以本更新和 [PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md](./PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md) 为准。
|
||||
|
||||
日期:`2026-04-21`
|
||||
|
||||
@@ -8,17 +8,25 @@
|
||||
|
||||
这份文档用于指导 `M2` 中以下两条任务的首版落地:
|
||||
|
||||
1. `实现密码登录`
|
||||
2. `实现账号自动创建 / 幂等登录兼容策略`
|
||||
1. `实现手机号密码登录`
|
||||
2. `移除密码登录自动注册 / 自动建号语义`
|
||||
|
||||
目标是先把当前 Node 已经稳定运行的 `/api/auth/entry` 语义迁到 Rust 工作区,并冻结:
|
||||
目标是把 `/api/auth/entry` 在 Rust 工作区冻结为手机号验证码账号的补充登录方式:
|
||||
|
||||
1. `api-server` 对外暴露的最小兼容接口。
|
||||
2. `module-auth` 负责的密码登录用例边界。
|
||||
3. 自动建号与并发幂等兼容规则。
|
||||
1. `api-server` 对外只暴露 `phone + password` 的最小接口。
|
||||
2. `module-auth` 只负责已存在手机号账号的密码校验。
|
||||
3. 密码入口不创建账号,不接收邮箱、用户名或叙世号。
|
||||
4. 登录成功后与 JWT、refresh cookie 的衔接方式。
|
||||
|
||||
## 2. 当前基线
|
||||
## 1.1 当前冻结结论
|
||||
|
||||
1. 密码登录不是注册入口。
|
||||
2. 密码登录是手机号验证码登录的补充方式。
|
||||
3. 只有已存在、已绑定手机号、并已设置密码的账号可以通过密码登录。
|
||||
4. 未知手机号、未设置密码、密码错误统一返回 `401 UNAUTHORIZED`,避免通过密码入口探测账号状态。
|
||||
5. 手机号验证码登录仍是新用户注册/首次登录的唯一入口。
|
||||
|
||||
## 2. 历史基线
|
||||
|
||||
当前 Node `/api/auth/entry` 主链已经具备如下语义:
|
||||
|
||||
@@ -29,7 +37,7 @@
|
||||
5. 同时创建 refresh session,并把原始 refresh token 写入 HttpOnly cookie。
|
||||
6. 并发创建同一用户名时,后到的请求会回退为“查已存在账号并校验密码”,不因唯一键冲突直接失败。
|
||||
|
||||
这条链路既是当前前端匿名/游客恢复的基础,也是真实 `/api/auth/entry` contract 的既有事实,因此 Rust 首版必须兼容。
|
||||
这条链路曾经是前端匿名/游客恢复的基础。2026-04-25 起该历史语义已废弃,Rust 当前实现必须以“手机号账号已设置密码后登录”为准,不再兼容密码自动建号。
|
||||
|
||||
## 3. 设计输入
|
||||
|
||||
@@ -41,12 +49,12 @@
|
||||
4. [PLATFORM_AUTH_JWT_ADAPTER_DESIGN_2026-04-21.md](./PLATFORM_AUTH_JWT_ADAPTER_DESIGN_2026-04-21.md)
|
||||
5. [PLATFORM_AUTH_REFRESH_COOKIE_ADAPTER_DESIGN_2026-04-21.md](./PLATFORM_AUTH_REFRESH_COOKIE_ADAPTER_DESIGN_2026-04-21.md)
|
||||
|
||||
关键冻结点:
|
||||
当前冻结点:
|
||||
|
||||
1. `password_hash` 当前继续由 `user_account` 承担,不进入 `auth_identity`。
|
||||
2. `sub` 必须是稳定 `user_id`。
|
||||
3. 登录成功后必须继续同时生成 access token 和 refresh session。
|
||||
4. 自动建号兼容必须保留,不能因为迁到 Rust 就删除。
|
||||
4. 密码登录不再保留自动建号兼容,旧开发游客自动建号链路必须迁出 `/api/auth/entry`。
|
||||
|
||||
## 4. 首版落地范围
|
||||
|
||||
@@ -54,14 +62,14 @@
|
||||
|
||||
1. `module-auth` 中的密码登录用例。
|
||||
2. `api-server` 中的 `POST /api/auth/entry`。
|
||||
3. 用户名校验、密码哈希校验与自动建号。
|
||||
3. 手机号归一化、密码哈希校验与未设置密码拒绝。
|
||||
4. 登录成功后的 access token 与 refresh cookie 主链打通。
|
||||
|
||||
本阶段明确不包含:
|
||||
|
||||
1. SpacetimeDB 真正的 `user_account` / `refresh_session` reducer 写入。
|
||||
2. `/api/auth/me`、`/api/auth/logout`、`/api/auth/refresh` 的正式业务闭环。
|
||||
3. 手机验证码与微信登录链路。
|
||||
3. 新增邮箱登录或独立密码注册链路。
|
||||
|
||||
## 5. crate 边界
|
||||
|
||||
@@ -69,9 +77,9 @@
|
||||
|
||||
负责:
|
||||
|
||||
1. 用户名与密码的领域校验。
|
||||
1. 手机号与密码的领域校验。
|
||||
2. 密码登录主用例。
|
||||
3. 自动建号与并发幂等兼容策略。
|
||||
3. 已存在手机号账号与已设置密码约束。
|
||||
4. 输出登录成功所需的最小用户快照。
|
||||
|
||||
不负责:
|
||||
@@ -106,11 +114,11 @@
|
||||
|
||||
### 6.1 请求体
|
||||
|
||||
固定沿用当前 contract:
|
||||
当前 contract:
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "guest_001",
|
||||
"phone": "13800138000",
|
||||
"password": "secret123"
|
||||
}
|
||||
```
|
||||
@@ -124,9 +132,9 @@
|
||||
"token": "<access-token>",
|
||||
"user": {
|
||||
"id": "user_xxx",
|
||||
"username": "guest_001",
|
||||
"displayName": "guest_001",
|
||||
"phoneNumberMasked": null,
|
||||
"username": "phone_xxx",
|
||||
"displayName": "138****8000",
|
||||
"phoneNumberMasked": "138****8000",
|
||||
"loginMethod": "password",
|
||||
"bindingStatus": "active",
|
||||
"wechatBound": false
|
||||
@@ -136,11 +144,11 @@
|
||||
|
||||
同时响应头必须写回 refresh cookie。
|
||||
|
||||
## 7. 用户名与密码规则
|
||||
## 7. 手机号与密码规则
|
||||
|
||||
当前阶段继续对齐 Node 基线:
|
||||
当前阶段固定:
|
||||
|
||||
1. `username` 只允许 `3` 到 `24` 位字母、数字、下划线。
|
||||
1. `phone` 只接受中国大陆手机号,服务端统一归一化为 `E.164` 后查询。
|
||||
2. `password` 长度必须在 `6` 到 `128` 位之间。
|
||||
|
||||
任一校验失败时:
|
||||
@@ -148,37 +156,30 @@
|
||||
1. 返回 `400 BAD_REQUEST`
|
||||
2. 错误文案继续保持中文
|
||||
|
||||
## 8. 自动建号与幂等兼容
|
||||
## 8. 登录校验规则
|
||||
|
||||
### 8.1 自动建号
|
||||
### 8.1 未知手机号
|
||||
|
||||
当 `username` 不存在时:
|
||||
当 `phone` 归一化后找不到账号时:
|
||||
|
||||
1. 用当前请求里的 `password` 生成密码哈希。
|
||||
2. 创建一条本地账号。
|
||||
3. `display_name = username`
|
||||
4. `login_provider = password`
|
||||
5. `account_status = active`
|
||||
6. `token_version = 1`
|
||||
1. 返回 `401 UNAUTHORIZED`。
|
||||
2. 不创建账号。
|
||||
3. 不写 `password_hash`。
|
||||
|
||||
### 8.2 已存在账号
|
||||
### 8.2 未设置密码
|
||||
|
||||
当 `username` 已存在时:
|
||||
当账号存在但 `password_login_enabled = false` 时:
|
||||
|
||||
1. 返回 `401 UNAUTHORIZED`。
|
||||
2. 不区分“未设置密码”和“密码错误”的外部文案。
|
||||
|
||||
### 8.3 已设置密码
|
||||
|
||||
当账号存在且已设置密码时:
|
||||
|
||||
1. 校验密码哈希。
|
||||
2. 校验失败返回 `401 UNAUTHORIZED`。
|
||||
3. 校验成功继续登录。
|
||||
|
||||
### 8.3 并发幂等兼容
|
||||
|
||||
若两个请求并发创建同一用户名:
|
||||
|
||||
1. 允许其中一个请求先创建成功。
|
||||
2. 后一个请求若命中唯一键冲突,不直接失败。
|
||||
3. 后一个请求必须重新查询该用户名。
|
||||
4. 若查到账号,则按“已存在账号”路径继续校验密码。
|
||||
|
||||
这保证了当前前端重复调用 `/api/auth/entry` 时可以恢复同一账号,而不是随机失败。
|
||||
3. 校验成功签发 access token 与 refresh cookie。
|
||||
|
||||
## 9. 首版存储策略
|
||||
|
||||
@@ -226,10 +227,10 @@
|
||||
|
||||
当前阶段至少覆盖:
|
||||
|
||||
1. 首次密码登录自动建号成功。
|
||||
2. 同用户名同密码可重复登录同一账号。
|
||||
3. 同用户名不同密码返回 `401`。
|
||||
4. 非法用户名返回 `400`。
|
||||
1. 未知手机号密码登录返回 `401`,且不创建账号。
|
||||
2. 已登录手机号账号设置密码后可用 `phone + password` 登录。
|
||||
3. 同手机号错误密码返回 `401`。
|
||||
4. 邮箱、用户名或叙世号作为密码登录标识返回 `400`。
|
||||
5. 登录成功时返回 access token。
|
||||
6. 登录成功时写回 refresh cookie。
|
||||
|
||||
@@ -239,7 +240,7 @@
|
||||
|
||||
1. `module-auth` 不再只是 README,占位被真实 crate 实现替换。
|
||||
2. `POST /api/auth/entry` 可在 Rust 侧独立跑通。
|
||||
3. 自动建号与幂等兼容行为可验证。
|
||||
3. 密码入口不注册、不接收邮箱/用户名的行为可验证。
|
||||
4. JWT 与 refresh cookie 登录成功主链打通。
|
||||
5. 文档、任务清单与测试同步完成。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user