ed76820e97
读完了两份 spec + 分派器,这分支的全貌清晰了。下面是可直接粘进 Gitea PR 的 MR 说明(标题 + 正文): 建议标题 feat(sms): 短信验证码可切换多 provider(极光/阿里云/创蓝),默认极光零改动 MR 正文(复制以下 markdown): ## 概述 把原单文件 `app/integrations/sms.py` 重构为**可切换 provider 包** `app/integrations/sms/`,在保留极光(默认、行为零改动)的基础上,新增两家验证码短信 provider: - **阿里云号码认证 dypns**(Mode A:阿里云生成/存储/校验验证码,核验免费) - **创蓝云智 253**(Mode B:本服务自管码,httpx 直连 + HMAC 签名) Provider 由 `SMS_PROVIDER` 按调用实时选择,默认 `jiguang`。短信=花钱 + 登录关键路径,故新 provider **opt-in、可灰度、秒级回退**,默认路径零变更。 ## 为什么 现有极光路径本地内存存码(多 worker 不共享,已是技术债),且单一供应商无法灰度/切换。引入 provider 抽象后:阿里云托管码可消除存码债,创蓝作为备选降低单点依赖,三家随配置切换与回退。 ## 改动内容 **架构(`app/integrations/sms/`)** | 文件 | 说明 | |---|---| | `__init__.py` | 对外仍暴露 `send_code/verify_code/SmsError`(auth 导入不变);按 `SMS_PROVIDER` **每次调用**分派;未知值回退 `jiguang` | | `base.py` | `SmsError`(status_code→HTTP) + provider 无关的 `mock_verify` | | `jiguang.py` | 原 `sms.py` 逻辑**原样迁入**,行为零改动(git 识别为 rename) | | `aliyun.py` | 新增,Mode A:`SendSmsVerifyCode` + `CheckSmsVerifyCode`,惰性加载 SDK | | `chuanglan.py` | 新增,Mode B:自管码 + `tpl/send` + HMAC 签名 | **两种验证码模式** - Mode A(阿里云):不本地存码,阿里云 `##code##` 托管生成+校验;本地仅留 per-phone 失败计数防爆破。 - Mode B(极光/创蓝):`secrets` 生成 N 位 → 进程内存 → 供应商只下发;本地一次性校验 + 失败 N 次作废。创蓝**复制**极光存码机器(不重构极光,零回归风险)。 **配置(`config.py` + `.env.example`)** - `SMS_PROVIDER = jiguang | aliyun | chuanglan`(默认 jiguang) - `ALIYUN_SMS_*`(AK/签名/模板/方案名/时长…) + `aliyun_sms_configured` 门控 - `CHUANGLAN_SMS_*`(账号/密码/模板/签名/endpoint…) + `chuanglan_sms_configured` 门控 - 复用现有 `SMS_MOCK / SMS_CODE_LENGTH / SMS_CODE_TTL_SEC / SMS_SEND_INTERVAL_SEC / SMS_MAX_VERIFY_ATTEMPTS` - 切到某 provider 却未配齐 → `send_code` 抛 `SmsError(503)`,不静默 **auth.py(最小改动)** - `verify_code` 现在可能抛 `SmsError`(阿里云降级 503)→ `sms_login`、`wechat_bind_phone_sms` 两处各包 `try/except SmsError → HTTPException`,与 `send_code` 现有写法一致。 **依赖** - `pyproject.toml` 增 `alibabacloud_dypnsapi20170525`(仅阿里云 provider 惰性 import;jiguang/chuanglan 不加载)。创蓝零新依赖(httpx + 标准库)。 **测试** - 新增 `test_sms_aliyun.py` / `test_sms_chuanglan.py`(均 monkeypatch 网络接缝,不发真短信) + `test_sms_dispatch.py`(分派/回退)。 - `test_auth.py` 相应更新。 - 现有测试走 `SMS_MOCK=true` 在分派层短路,不受影响。 **文档** - 设计 spec:`docs/superpowers/specs/2026-07-25-aliyun-sms-verify-design.md`、`2026-07-26-chuanglan-sms-verify-design.md` - 接口调研:`docs/integrations/aliyun/*`、`docs/integrations/chuanglan/tpl-send.md`、`docs/integrations/sms.md` ## 兼容性 & 回退 - **默认 `SMS_PROVIDER=jiguang`,线上行为与现状完全一致**;不改极光逻辑、不动 API 层频控与测试账号短路。 - 切阿里云/创蓝仅改环境变量,出问题秒切回极光;未知 `SMS_PROVIDER` 一律回退极光,防误配打挂登录。 --------- Co-authored-by: guke <guke@autohome.com.cn> Reviewed-on: #188
63 lines
1.3 KiB
Plaintext
63 lines
1.3 KiB
Plaintext
__pycache__/
|
|
*.py[cod]
|
|
*$py.class
|
|
|
|
.venv/
|
|
venv/
|
|
env/
|
|
|
|
*.egg-info/
|
|
build/
|
|
dist/
|
|
.eggs/
|
|
|
|
.pytest_cache/
|
|
.ruff_cache/
|
|
.mypy_cache/
|
|
|
|
.env
|
|
.env.*
|
|
!.env.example
|
|
|
|
*.db
|
|
*.db-journal
|
|
*.db-shm
|
|
*.db-wal
|
|
# data/ 整体不入库(运行时数据/上传文件/大二进制)。例外:邀请落地页 dl.html 及其
|
|
# 引用的静态插画(coupon-page-bg.png 底图 + sb-brand.png logo)——既是生产落地页资产
|
|
# 又是本地测试资产,纳入 git 便于同事一致测试、且随部署进生产 /media(否则线上 404→落地页毛坯)。
|
|
# (见 docs/邀请功能-实现原理与本地测试.md)。其余(avatars/ / *.apk / app.db 等)仍忽略。
|
|
data/*
|
|
!data/media/
|
|
data/media/*
|
|
!data/media/dl.html
|
|
!data/media/taobao_landing.jpg
|
|
!data/media/coupon-page-bg.png
|
|
!data/media/sb-brand.png
|
|
|
|
secrets/*
|
|
!secrets/.gitkeep
|
|
*.pem
|
|
*.key
|
|
|
|
.DS_Store
|
|
.idea/
|
|
.vscode/
|
|
*.swp
|
|
|
|
# 运行日志(run.sh 输出, 不入库)
|
|
*.log
|
|
logs/
|
|
|
|
# 本地 admin server(端口 8771)Windows 启动脚本,个人调试用,不入库
|
|
/run8771.bat
|
|
|
|
# Claude Code 自动持久化的权限 allowlist / 个人本地设置(会话专属,不入库)。
|
|
# 需要团队共享的 Claude 配置(commands/ 等)可单独 git add -f,不受此忽略影响。
|
|
.claude/settings.json
|
|
.claude/settings.local.json
|
|
tests/meituan_coupon_bj.tsv
|
|
tests/meituan_coupon_data.tsv
|
|
tests/meituan_coupon_fz.tsv
|
|
tests/meituan_coupon_xm.tsv
|