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:
@@ -0,0 +1,105 @@
|
||||
# client-wechat-login Specification
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: A2 微信公众号登录接口
|
||||
|
||||
系统 MUST 提供 `POST /api/c/v1/auth/wechat-login`,使用公众号 OAuth code + `asset_token` 完成登录。
|
||||
|
||||
- HTTP Method + Path: `POST /api/c/v1/auth/wechat-login`
|
||||
- 请求体字段:
|
||||
- `code` string,MUST,微信 OAuth 授权码
|
||||
- `asset_token` string,MUST,A1 返回的资产令牌
|
||||
- 响应体字段:
|
||||
- `token` string,MUST,登录 JWT
|
||||
- `need_bind_phone` bool,MUST,是否需要绑定手机号
|
||||
- `is_new_user` bool,MUST,是否新创建用户
|
||||
- 错误码:
|
||||
- `1002` token 无效或过期(asset_token/JWT)
|
||||
- `1040` 微信授权失败
|
||||
- `1006` 参数错误
|
||||
|
||||
#### Scenario: 公众号登录成功
|
||||
- **WHEN** 客户端提交有效 `code` 与有效 `asset_token`
|
||||
- **THEN** 系统 SHALL 调用公众号 OAuth 获取 `openid` 与可选 `unionid`
|
||||
- **THEN** 系统 SHALL 执行客户查找/创建/合并逻辑
|
||||
- **THEN** 系统 SHALL 绑定资产并签发登录 token
|
||||
|
||||
### Requirement: A3 微信小程序登录接口
|
||||
|
||||
系统 MUST 提供 `POST /api/c/v1/auth/miniapp-login`,使用小程序 `jscode2session` + `asset_token` 完成登录。
|
||||
|
||||
- HTTP Method + Path: `POST /api/c/v1/auth/miniapp-login`
|
||||
- 请求体字段:
|
||||
- `code` string,MUST,小程序登录凭证
|
||||
- `asset_token` string,MUST,A1 返回的资产令牌
|
||||
- 响应体字段:
|
||||
- `token` string,MUST,登录 JWT
|
||||
- `need_bind_phone` bool,MUST
|
||||
- `is_new_user` bool,MUST
|
||||
- 错误码:
|
||||
- `1002` token 无效或过期
|
||||
- `1040` 微信授权失败
|
||||
- `1006` 参数错误
|
||||
|
||||
#### Scenario: 小程序登录成功
|
||||
- **WHEN** 客户端提交有效小程序 `code` 与有效 `asset_token`
|
||||
- **THEN** 系统 SHALL 调用 `jscode2session` 获取 `openid` 与可选 `unionid`
|
||||
- **THEN** 系统 SHALL 执行与 A2 一致的客户查找/创建/合并、资产绑定与签发逻辑
|
||||
|
||||
### Requirement: asset_token 校验与资产解析
|
||||
|
||||
系统 SHALL 在 A2/A3 登录前强制校验 `asset_token`,并解析出 `asset_type` + `asset_id`。
|
||||
|
||||
#### Scenario: asset_token 无效
|
||||
- **WHEN** `asset_token` 签名不合法或已过期
|
||||
- **THEN** 系统 MUST 拒绝登录并返回 `1002`
|
||||
|
||||
#### Scenario: asset_token 有效
|
||||
- **WHEN** `asset_token` 可被成功解析
|
||||
- **THEN** 系统 SHALL 使用解析出的资产信息继续登录流程
|
||||
|
||||
### Requirement: 客户查找/创建/合并逻辑
|
||||
|
||||
系统 MUST 按以下顺序处理客户归属:
|
||||
|
||||
1. 先查 `PersonalCustomerOpenID`:`(app_id, open_id)`;
|
||||
2. 未命中且存在 `unionid` 时按 `unionid` 回查并复用客户;
|
||||
3. 仍未命中时创建新 `PersonalCustomer` 与 OpenID 记录。
|
||||
|
||||
#### Scenario: openid 命中既有客户
|
||||
- **WHEN** `(app_id, open_id)` 已存在
|
||||
- **THEN** 系统 SHALL 直接复用对应 `customer_id`
|
||||
|
||||
#### Scenario: openid 未命中但 unionid 命中
|
||||
- **WHEN** `(app_id, open_id)` 不存在且 `unionid` 命中历史记录
|
||||
- **THEN** 系统 SHALL 复用已存在客户
|
||||
- **THEN** 系统 SHALL 新增当前 `app_id + open_id` 记录
|
||||
|
||||
#### Scenario: openid/unionid 均未命中
|
||||
- **WHEN** 无任何匹配记录
|
||||
- **THEN** 系统 SHALL 创建新客户并写入 OpenID 记录
|
||||
|
||||
### Requirement: 登录后资产绑定
|
||||
|
||||
系统 SHALL 在 A2/A3 每次登录时创建一条 `PersonalCustomerDevice` 绑定记录,且 MUST 允许同一资产被多个客户绑定。
|
||||
|
||||
#### Scenario: 已有绑定时再次登录
|
||||
- **WHEN** 同一客户再次登录同一资产
|
||||
- **THEN** 系统 SHALL 记录本次登录绑定关系(按实现可去重或追加历史)
|
||||
|
||||
#### Scenario: 不同客户绑定同一资产
|
||||
- **WHEN** 资产已被其他客户绑定
|
||||
- **THEN** 系统 MUST 允许新增绑定,不得覆盖已有客户绑定关系
|
||||
|
||||
### Requirement: 登录响应与手机号绑定开关
|
||||
|
||||
系统 MUST 在登录响应中返回 `need_bind_phone`,该值由 `client.require_phone_binding` 与客户手机号绑定状态共同决定。
|
||||
|
||||
#### Scenario: 要求手机号绑定且未绑定
|
||||
- **WHEN** 配置 `client.require_phone_binding=true` 且客户未绑定手机号
|
||||
- **THEN** 登录响应 MUST 返回 `need_bind_phone=true`
|
||||
|
||||
#### Scenario: 已绑定手机号或配置关闭
|
||||
- **WHEN** 客户已绑定手机号或 `client.require_phone_binding=false`
|
||||
- **THEN** 登录响应 MUST 返回 `need_bind_phone=false`
|
||||
Reference in New Issue
Block a user