feat: 实现 C 端完整认证系统(client-auth-system)

实现面向个人客户的 7 个认证接口(A1-A7),覆盖资产验证、
微信公众号/小程序登录、手机号绑定/换绑、退出登录完整流程。

主要变更:
- 新增 PersonalCustomerOpenID 模型,支持多 AppID 多 OpenID 管理
- 实现有状态 JWT(JWT + Redis 双重校验),支持服务端主动失效
- 扩展微信 SDK:小程序 Code2Session + 3 个 DB 动态工厂函数
- 实现 A1 资产验证 IP 限流(30/min)和 A4 三层验证码限流
- 新增 7 个错误码(1180-1186)和 6 个 Redis Key 函数
- 注册 /api/c/v1/auth/* 下 7 个端点并更新 OpenAPI 文档
- 数据库迁移 000083:新建 tb_personal_customer_openid 表
This commit is contained in:
2026-03-19 11:33:41 +08:00
parent ec86dbf463
commit df76e33105
35 changed files with 4348 additions and 1362 deletions

View File

@@ -0,0 +1,94 @@
# client-phone-binding Specification
## ADDED Requirements
### Requirement: A4 发送验证码接口
系统 MUST 提供无认证验证码接口 `POST /api/c/v1/auth/send-code`,并复用现有验证码服务。
- HTTP Method + Path: `POST /api/c/v1/auth/send-code`
- 请求体字段:
- `phone` stringMUST手机号
- `scene` stringMUST业务场景`bind_phone` / `change_phone_old` / `change_phone_new`
- 响应体字段:
- `cooldown_seconds` intMUST本次发送后的冷却秒数
- 错误码:
- `1006` 参数错误
- `1003` 请求过于频繁(触发任一限流)
- `1050` 短信发送失败
#### Scenario: 发送成功
- **WHEN** 手机号格式合法且未触发限流
- **THEN** 系统 SHALL 发送验证码并返回冷却时间
### Requirement: A4 限频规则
系统 SHALL 对 A4 实施三层限频:手机号 60 秒冷却、同 IP 每小时 20 次、同手机号每日 10 次。
#### Scenario: 60 秒内重复发送
- **WHEN** 同一手机号在 60 秒冷却内再次请求
- **THEN** 系统 MUST 返回 `1003`
#### Scenario: 同 IP 超过小时阈值
- **WHEN** 同一 IP 在 1 小时内发送次数超过 20
- **THEN** 系统 MUST 返回 `1003`
#### Scenario: 同手机号超过日阈值
- **WHEN** 同一手机号在当日发送次数超过 10
- **THEN** 系统 MUST 返回 `1003`
### Requirement: A5 首次绑定手机号接口
系统 MUST 提供需认证接口 `POST /api/c/v1/auth/bind-phone`,仅允许首次绑定。
- HTTP Method + Path: `POST /api/c/v1/auth/bind-phone`
- 请求体字段:
- `phone` stringMUST新手机号
- `code` stringMUST验证码
- 响应体字段:
- `phone` stringMUST已绑定手机号
- `bound_at` stringMUST绑定时间
- 错误码:
- `1001` 缺失认证令牌
- `1002` 认证令牌无效
- `1006` 参数错误
- `1035` 验证码错误或过期
- `1037` 手机号已被绑定
- `1038` 已绑定手机号不可重复绑定
#### Scenario: 首次绑定成功
- **WHEN** 客户已登录、验证码正确且手机号未被占用
- **THEN** 系统 SHALL 完成手机号首次绑定并返回绑定信息
#### Scenario: 已绑定用户再次调用绑定
- **WHEN** 当前客户已存在绑定手机号
- **THEN** 系统 MUST 返回 `1038`
### Requirement: A6 换绑手机号接口
系统 MUST 提供需认证接口 `POST /api/c/v1/auth/change-phone`,并执行旧手机号与新手机号双验证码校验。
- HTTP Method + Path: `POST /api/c/v1/auth/change-phone`
- 请求体字段:
- `old_phone` stringMUST旧手机号
- `old_code` stringMUST旧手机号验证码
- `new_phone` stringMUST新手机号
- `new_code` stringMUST新手机号验证码
- 响应体字段:
- `phone` stringMUST换绑后的手机号
- `changed_at` stringMUST换绑时间
- 错误码:
- `1001` 缺失认证令牌
- `1002` 认证令牌无效
- `1006` 参数错误
- `1035` 验证码错误或过期
- `1037` 新手机号已被绑定
- `1039` 旧手机号不匹配
#### Scenario: 换绑成功
- **WHEN** 登录客户提交正确旧/新验证码且新手机号未占用
- **THEN** 系统 SHALL 更新绑定手机号为新手机号
#### Scenario: 旧手机号校验失败
- **WHEN** `old_phone` 与当前客户绑定手机号不一致或 `old_code` 错误
- **THEN** 系统 MUST 拒绝换绑并返回对应错误码