93f052535e
按 mentor 要求精简 SMS 登录链路的防刷策略,只保留两道主策略: - 单号 60s 冷却(发码,SMS_SEND_INTERVAL_SEC) - 单设备(device_id + IP)每小时 5 次频控(发码 + 登录,enforce_rate_limit) 删除两道: - 单号每日发送上限(SMS_DAILY_LIMIT_PER_PHONE) - 登录接口纯 IP 20 次/分钟限流(rate_limit 依赖) 验证码安全底线保留(一次性使用 + 输错 SMS_MAX_VERIFY_ATTEMPTS 次即作废), 属验证码正确性、不算限流策略,不在精简范围。 顺带清理:sms.py 移除 _daily_count/_today 及 datetime 导入;config.py 删常量; auth.py 清理变为无用的 Depends/rate_limit 导入;同步 docs/integrations/sms.md 与 docs/后端技术实现.md 的防刷说明(并修正 sms.md 里已过时的 /sms/send rate_limit 描述)。 影响:单号发码上限由 10 条/天放宽为仅受 60s 冷却约束;登录撞库防护改由设备频控 + 验证码错误次数上限兜底。test_auth.py 相应用例已删除/更新,auth 测试全绿。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: zzhyyyyy <2685922758@qq.com> Reviewed-on: #109 Co-authored-by: zhuzihao <zhuzihao@wonderable.ai> Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
3.8 KiB
3.8 KiB
短信验证码(sms)
文件:
app/integrations/sms.py| 关联接口:auth-sms-send · auth-sms-login | ← 集成索引
作用
手机号 + 验证码登录的验证码发送 / 校验。已接极光短信 REST,由 SMS_MOCK 切 mock / real。
mock(SMS_MOCK=true,默认 / 开发测试) |
real(SMS_MOCK=false,生产) |
|
|---|---|---|
| 发送 | 不真发,验证码打日志 | 调极光 /v1/messages 真发 |
| 校验 | 放行任意 6 位数字(测试便利) | 比对本服务存的码(一次性 / 过期 / 防爆破) |
为什么是"自己生成码"模式
极光有两种验证码玩法:① /v1/codes 极光生成 + /codes/{msg_id}/valid 极光校验;② /v1/messages 本服务生成码、极光只负责发。选 ②:校验本地完成(不依赖极光二次往返)、有效期/错误次数/作废完全可控、跟原 mock 口子结构一致。
函数 / 异常
| 函数 | 行为 |
|---|---|
send_code(phone) -> int |
防刷检查(冷却)→ secrets 生成 N 位码 → 预占(冷却/存码)→ mock 打日志 / real 调极光 → 失败回滚预占。返回距下次可发秒数 |
verify_code(phone, code) -> bool |
mock 放行任意 6 位;real 比对存码,匹配即作废,失败累计到上限作废 |
SmsError(msg, status_code) |
status_code 决定 HTTP 码:过频 429、供应商失败 503、号码无效 400 |
配置
| 配置项 | 默认 | 说明 |
|---|---|---|
SMS_MOCK |
true |
mock / real 切换。生产置 false |
SMS_CODE_TTL_SEC |
300 | 验证码有效期(秒),与极光模板文案"5分钟"一致 |
SMS_SEND_INTERVAL_SEC |
60 | 单号两次发送最小间隔(冷却) |
SMS_SEND_ENDPOINT |
极光 /v1/messages |
短信发送地址 |
SMS_SIGN_ID |
31729 | 极光签名 ID |
SMS_TEMPLATE_ID |
1 | 极光模板 ID(变量名 code) |
SMS_CODE_LENGTH |
6 | 验证码位数(本服务生成;前端 code 4-8 位兼容) |
SMS_MAX_VERIFY_ATTEMPTS |
5 | 单码最多校验失败次数,超过作废(防爆破) |
鉴权复用极光一键登录:
/v1/messages用base64(JG_APP_KEY:JG_MASTER_SECRET)做 HTTP Basic Auth——短信与一键登录是同一个极光应用(同 AppKey)。上线不需要额外凭证,只需SMS_MOCK=false(JG_*一键登录已配)。
防刷(短信花钱 + /sms/send 在登录前无法 JWT 鉴权)
2026-07-03 精简:登录风控只留「单号冷却 + 单设备频控」两道主策略(删单号每日上限、删登录纯 IP
rate_limit);单码失败上限属验证码安全底线,保留。
- 单号
SMS_SEND_INTERVAL_SEC冷却(单号维度) - 单设备(
device_id+ IP)每小时频控:/sms/send≤SMS_SEND_MAX_PER_HOUR_PER_DEVICE(5)、/sms/login≤SMS_LOGIN_MAX_PER_HOUR(5)——堵「换号绕开单号冷却」+ 挡登录撞库,在app/api/v1/auth.py内enforce_rate_limit - 单码校验失败
SMS_MAX_VERIFY_ATTEMPTS次即作废 + 验过即作废(一次性) - 运维侧建议在极光控制台叠加:IP 白名单(只许服务器 IP)+ 防轰炸设置
极光错误码(节选,映射在 _send_via_jiguang)
| code | 含义 | 处理 |
|---|---|---|
| 50014 | 余额不足 | logger.critical 告警 + 503 |
| 50009 | 极光侧超频 | 429 |
| 50006 | 手机号无效 | 400 |
| 其他 | — | 503 |
上线步骤
- 极光控制台:企业实名 + 短信充值 + 签名审核(
sign_id=31729)+ 模板审核(temp_id=1)——均已就绪 .env设SMS_MOCK=false(JG_APP_KEY/JG_MASTER_SECRET一键登录已配)- 真机发一条验证:收到短信 + 能登录
已知局限
验证码存进程内存:单 worker uvicorn 够用;重启丢码(用户重发即可);多 worker / 多机不共享 → 冷却 / 校验失效,扩 worker 前迁移到 DB/Redis。见 待办与技术债。