feat(server-rs): 接入真实短信验证码链路

This commit is contained in:
2026-04-23 00:09:51 +08:00
parent 1223f597d2
commit 9cb996b80e
11 changed files with 1274 additions and 40 deletions

View File

@@ -0,0 +1,163 @@
# Axum 手机验证码真实短信 Provider 接入设计
日期:`2026-04-22`
## 1. 文档目的
这份文档用于冻结 Rust `api-server + module-auth + platform-auth` 切换到真实短信链路时的最小可编码边界,解决当前 `module-auth` 仍固定使用 mock 验证码 `123456`,导致 `server-rs` 无法接入真实短信发送与真实验证码校验的问题。
## 2. 当前问题
截至 `2026-04-22`Rust 侧手机号登录存在以下状态:
1. `POST /api/auth/phone/send-code` 已存在,但 `module-auth` 内部仍写死 `123456`
2. `POST /api/auth/phone/login` 校验的是本地内存快照里的固定验证码,不是真实短信平台生成的验证码。
3. 即使把发送动作切到真实阿里云短信,如果校验仍留在本地 mock整条登录链仍然不可用。
## 3. 本次目标
本次必须达成:
1. Rust 侧短信 provider 支持 `mock``aliyun` 两种模式。
2. `send-code``aliyun` 模式下调用阿里云 `SendSmsVerifyCode`
3. `phone/login``wechat/bind-phone``aliyun` 模式下调用阿里云 `CheckSmsVerifyCode`
4. `module-auth` 不再保存验证码明文,只保存发送冷却、有效期和失败次数所需的最小快照。
5. `shared-contracts` 公开响应 contract 维持不变,仍只返回:
- `ok`
- `cooldownSeconds`
- `expiresInSeconds`
- `providerRequestId`
## 4. crate 边界
### 4.1 `platform-auth`
负责:
1. 短信 provider 配置结构。
2. `mock / aliyun` provider 实现。
3. 阿里云 RPC 请求签名、发送与校验。
4. provider 级错误归一化。
### 4.2 `module-auth`
负责:
1. 手机号归一化。
2. 发送冷却与验证码快照 TTL。
3. 校验失败次数累加与耗尽删除。
4. 手机号用户创建、复用、微信补绑归并。
### 4.3 `api-server`
负责:
1. 从环境变量读取短信 provider 配置。
2. 构建 `SmsAuthProvider` 并注入 `PhoneAuthService`
3. 把领域错误映射成 HTTP 错误。
## 5. 配置设计
新增或继续使用以下环境变量:
1. `SMS_AUTH_ENABLED`
2. `SMS_AUTH_PROVIDER`
- `mock`
- `aliyun`
3. `ALIYUN_SMS_ENDPOINT`
- 默认 `dypnsapi.aliyuncs.com`
4. `ALIYUN_SMS_ACCESS_KEY_ID`
5. `ALIYUN_SMS_ACCESS_KEY_SECRET`
6. `ALIYUN_SMS_SIGN_NAME`
7. `ALIYUN_SMS_TEMPLATE_CODE`
8. `ALIYUN_SMS_TEMPLATE_PARAM_KEY`
- 默认 `code`
9. `ALIYUN_SMS_COUNTRY_CODE`
- 默认 `86`
10. `ALIYUN_SMS_SCHEME_NAME`
11. `ALIYUN_SMS_CODE_LENGTH`
- 默认 `6`
12. `ALIYUN_SMS_CODE_TYPE`
- 默认 `1`
13. `ALIYUN_SMS_VALID_TIME_SECONDS`
- 默认 `300`
14. `ALIYUN_SMS_INTERVAL_SECONDS`
- 默认 `60`
15. `ALIYUN_SMS_DUPLICATE_POLICY`
- 默认 `1`
16. `ALIYUN_SMS_CASE_AUTH_POLICY`
- 默认 `1`
17. `ALIYUN_SMS_RETURN_VERIFY_CODE`
- 默认 `false`
18. `SMS_AUTH_MOCK_VERIFY_CODE`
- 默认 `123456`
## 6. provider 行为
### 6.1 `mock`
1. 发送验证码时不访问外部网络。
2. 返回固定 `mock-request-id`
3. 校验时使用内存中的 mock 验证码。
### 6.2 `aliyun`
1. 发送验证码调用 `SendSmsVerifyCode`
2. 校验验证码调用 `CheckSmsVerifyCode`
3. 使用阿里云 RPC 签名口径:
- `SignatureMethod=HMAC-SHA1`
- `SignatureVersion=1.0`
4. 当前仍只支持中国大陆手机号。
## 7. 状态与快照
`module-auth` 内部验证码快照保留:
1. `phone_number`
2. `scene`
3. `expires_at`
4. `last_sent_at`
5. `failed_attempts`
明确不再保留:
1. 验证码明文
2. 验证码 hash
校验流程改为:
1. 先检查是否存在活跃快照。
2. 再检查是否过期。
3. 再调用 provider 做真实验证码校验。
4. 校验失败时累加失败次数。
5. 达到上限时删除快照并返回 `429`
6. 校验成功后删除快照。
## 8. 错误语义
1. 手机号格式错误:`400`
2. 验证码格式错误:`400`
3. 验证码不存在或已过期:`400`
4. 校验失败:`400`
5. 验证码错误次数耗尽:`429`
6. 阿里云配置缺失:`500`
7. 阿里云上游失败:`502`
## 9. 测试要求
至少覆盖:
1. `mock` provider 的发送与登录仍可跑通。
2. `aliyun` provider 缺配置时会在服务初始化阶段报错。
3. 发送冷却逻辑不依赖验证码明文仍然有效。
4. 校验失败次数耗尽后会删除快照。
5. `send-code` 成功时仍返回既有 contract。
## 10. 非目标
本次明确不做:
1. 短信送达回执接口
2. `sms_auth_event` 真实持久化
3. 图形验证码
4. 更细粒度的 provider 错误码透传 DTO

View File

@@ -19,6 +19,7 @@
- [AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md](./AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md)`/api/auth/sessions` 会话列表设计,冻结当前设备识别、多端登录字段映射、`clientLabel` 兼容策略与 Rust 首版接口边界。
- [PHONE_AUTH_AXUM_MINIMAL_FLOW_DESIGN_2026-04-21.md](./PHONE_AUTH_AXUM_MINIMAL_FLOW_DESIGN_2026-04-21.md):手机号验证码登录最小闭环设计,冻结 mock 验证码规则、`send-code` / `phone/login` contract 与 crate 边界。
- [PHONE_AUTH_AXUM_RATE_LIMIT_AND_FAILURE_DESIGN_2026-04-21.md](./PHONE_AUTH_AXUM_RATE_LIMIT_AND_FAILURE_DESIGN_2026-04-21.md):手机号验证码冷却与失败次数限制设计,冻结同手机号同场景发送冷却、错误次数耗尽、`429``Retry-After` contract。
- [PHONE_AUTH_AXUM_REAL_SMS_PROVIDER_DESIGN_2026-04-22.md](./PHONE_AUTH_AXUM_REAL_SMS_PROVIDER_DESIGN_2026-04-22.md)??? Rust `api-server + module-auth + platform-auth` ?????? provider ? crate ???????????/????????????
- [WECHAT_LOGIN_AXUM_IMPLEMENTATION_DESIGN_2026-04-21.md](./WECHAT_LOGIN_AXUM_IMPLEMENTATION_DESIGN_2026-04-21.md)Rust `api-server` 微信登录实现设计,冻结微信 provider 接入、系统 JWT 签发边界、`wechat/start` / `wechat/callback` / `wechat/bind-phone` 闭环,以及与后续 `SpacetimeDB` claims 透传的关系。
- [WECHAT_LOGIN_REAL_INTEGRATION_RUNBOOK_2026-04-21.md](./WECHAT_LOGIN_REAL_INTEGRATION_RUNBOOK_2026-04-21.md):微信登录从本地 mock 到真实微信开放平台联调的执行手册,覆盖环境变量、回调域名、代理头要求、验证步骤与常见失败排查。
- [PASSWORD_ENTRY_FLOW_DESIGN_2026-04-21.md](./PASSWORD_ENTRY_FLOW_DESIGN_2026-04-21.md):密码登录与自动建号落地设计,冻结 `/api/auth/entry`、幂等兼容策略、模块边界以及与 JWT / refresh cookie 的衔接方式。