Files
airz-uniapp/docs/短信账户功能开发-20261012.md
T
hujun c95482a0f3 feat: 实现协议全文与同意记录功能
新增协议全文后台管理、版本化发布及本人同意记录功能,支持可撤销授权;完善资料与授权相关边界提示,调整评估提交时的资料与授权校验逻辑,同步更新相关页面文案与路由。
2026-10-14 14:53:13 +08:00

70 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 短信账户功能开发记录
2026-10-12,按用户“先写相关代码”的要求完成短信登录/首次注册、登录后验证码改密及原/新手机号双验证换绑的后端实现。供应商、已审核签名及模板暂缺,配置默认关闭;本轮未发送真实短信、连接生产或部署,未提交/推送。
现有小程序页面和请求契约可复用,本轮没有修改前端运行代码、融资评估28项输入或同事负责的产品机构库。已回撤的产品AI条件分析与人工复核不恢复。AUTH-001真实渠道仍阻塞,AUTH-002/004内部代码已接通,完整任务和正式验收仍未完成。
## 已实现行为
- 验证码采用六位安全随机数字、300秒有效期、同号码60秒冷却;每小时号码最多10次、IP最多30次,错误最多5次。Redis仅保存HMAC摘要,号码、IP和用途/账户上下文的键也作摘要处理。
- 登录验证码绑定登录用途和号码;安全验证码绑定用途、本人账户及发送时的当前手机号,不能跨账户、用途或换绑后的身份复用。
- 发送先预留,供应商明确确认成功后才激活;失败或结果未知时不产生可用验证码,冷却和限额仍保留。迟到失败不能删除后续新挑战。
- 单码/双码通过Lua原子核销;换绑任一码错误不消耗另一正确码,重复/并发最多成功一次。已核销后SQL、Hook或Token存储失败不恢复验证码,须重新发送。
- 首次短信登录生成随机未知初始密码,沿用现有密码哈希、Token及注册逻辑;邮箱为空、昵称为“融资用户”、积分为零。已有正常账户直接登录,禁用账户拒绝。
- 验证码改密须登录本人,不新增匿名找回密码;新密码8–32位且含字母和数字、不含空格。改密和换绑均撤销本人全部会话,要求重新登录。
- 换绑检查同号码及号码占用,复用现有手机号唯一索引,无DDL或迁移;账户行锁内再次核对会话和当前号码,历史评估快照不改写。密码登录也在行锁内重核号码,防止换绑后的旧号码并发重建会话。
## 接口
路径均以 `/api/v1` 为前缀,请求为JSON;安全操作使用已有Bearer鉴权。
| 方法/路径 | 请求字段 | 行为 |
| --- | --- | --- |
| POST `/auth/sms-code` | `phone`、`purpose: login` | 发送登录验证码,成功返回 `retryAfter`/`expiresIn` |
| POST `/auth/sms-login` | `phone`、`code` | 登录/首次注册,返回原会话及profile契约 |
| POST `/account/security/sms-code` | `purpose: password / phone-current / phone-new`、`newPhone` | 前两种只发给本人当前号码;新号码用途须提供有效且未占用的新号码 |
| PUT `/account/password` | `verification: sms`、`newPassword`、`code`,兼容页面发送的空 `oldPassword` | 本人短信验证改密;原密码验证分支保留 |
| PUT `/account/phone` | `newPhone`、`currentCode`、`newCode` | 原/新号码同时验证后换绑 |
改密/换绑成功返回 `reLoginRequired: true`。短信未启用或缺少可用Provider时,认证后的请求及公开短信入口返回503/`SMS_NOT_CONFIGURED`;未登录的安全操作仍返回401。关闭配置在供应商Hook及短信Redis连接之前生效,不发送、不生成验证码、不注册账户;原密码登录、资料及头像功能可继续使用。
## 后续供应商接入
后端仓库为 `D:/AAdesk/202609/airz`,新增服务 `application/common/library/SmsVerification.php` 和 `AccountSms.php`;`application/extra/sms_verification.php` 中的 `enabled` 固定为 `false`。
供应商实现以下契约,通过正常扩展Hook `sms_verification_provider` 返回Provider实例,配置项作为Hook参数传入:
```php
namespace app\common\library\smsverification;
interface Provider
{
public function available(): bool;
public function send(string $phone, string $code, string $purpose): bool;
}
```
`available()` 只在凭据、已审核签名、用途模板均可用时返回true;`send()` 按四种用途映射模板并限制超时,只有供应商明确接受该次发送才返回true。异常、超时或未知结果不能当成功,也不能自动重试未知发送。日志须屏蔽号码、验证码和凭据;密钥通过环境配置注入,不存仓库。短信摘要秘密由已有服务端 `token.key` 派生,复用Token的Redis配置和独立 `tokenprefix + sms:` 命名空间。
缺少Provider时默认使用 `UnavailableProvider`。当前没有真实供应商实现、生产模拟发送开关或固定验证码;测试替身只在tests目录中、显式隔离bootstrap下使用。资料齐备后补Provider适配及真实渠道/目标端验证,再单独安排后端发布;本轮代码完成不等于短信已经上线。
## 验证证据
全新本机MySQL5.7.26/Redis DB15、26张空合成表、独立ROOT及命名空间,未读取默认生产 `.env`。四套最终通过结果如下,不重复累计中途运行及专项检查:
| 入口 | 最终回执 | 检查数 | 本机HTTP请求 |
| --- | --- | ---: | ---: |
| `tests/sms_verification.php` | `sms-green-1` | 71 | 0 |
| `tests/account_sms.php` | `account-green-4` | 271 | 54 |
| `tests/api_session.php` | `session-regression-1` | 284 | 70 |
| `tests/api_profile.php` | `profile-regression-1` | 268 | 76 |
| 合计 | 四套入口 | 894 | 200 |
覆盖关闭零写入、限流/过期/错误上限、摘要存储、发送失败、用途/账户隔离、重复及并发核销、首次注册、双码换绑、全会话撤销、禁用账户、Hook/SQL/Redis故障及原密码登录/资料/头像回归。旧号码并发登录缺陷已通过红测试复现并修正;独立专项27项不另计入上表。新增双worker竞争验证一次注册、号码唯一归属、赢家Token撤销及输家号码/Token保持;未强制两方同时通过占用预检,不宣称确定覆盖唯一索引冲突分支。独立只读复审未发现P1/P2问题。
本轮12个PHP文件语法检查和两仓diff检查通过。未改前端运行代码,未重新编译小程序;真实短信到达、渠道错误码/超时、平台及多设备流程仍待供应商接入后验证。
私密归档:`D:/AAdesk/202609/airz-backups/account-sms/1791773313671`。脱敏测试输出及单套JSON、`verification.json`、`cleanup.json` 和进程退出回执保留。每套测试后表行和Redis核空、结构及8原触发器保持;最终仅删除本轮精确合成数据库,关闭所属两服务并释放端口。395份屏蔽回执显示真实模型客户端加载0次;短信测试JSON夹具和本轮生成Python缓存已精确清理,归档及证据保留。该归档包含私密配置及历史失败诊断,不整体共享,不直接复跑已清理环境。
下一步在短信资料未齐时,可继续其他已授权功能;接入短信时复用本契约补供应商适配,不需要改动融资录入内容或产品机构库。