Files
meida_backend/packages/identity
xsl cf9d500bfa feat(identity): phone SMS login with triple rate limiting and anti-abuse
SmsSender Protocol(fake/tencent)+ 验证码生命周期(哈希存储/一次性/
5 次作废)+ 号码-IP-设备三重频控 + 掩码纪律(FR-ACC-04/14,TD-32;
真实发送待签名审核)。

实现:packages/identity/sms_login.py(SmsStore/SmsSender 双 Protocol、
FakeSmsSender 打日志、TencentSmsSender 包官方 SDK 失败映射 61000、
SmsAuthService 验证码生命周期 + UTC+8 时段桶频控);路由 POST
/auth/sms/send、POST /auth/sms/verify(provider="phone" 映射 +
issue_session + TokenPairResponse,与华为通道零耦合)。测试:单测 37 个
(内存 dict 实现 store、注入时钟模拟 TTL;号码规范化/掩码/频控矩阵/
验证码四要素/腾讯通道桩测),集成 7 个(send→verify 双令牌闭环、同号
同 user、脚本化刷量 11 发第 11 次 42911、IP/设备维度、错 5 次作废)。
门禁:ruff/mypy(identity+apps/api)/lint-imports 全绿,单测 275 通过、
集成 23 通过。

偏差说明:
1. SmsSender.send_code 收 (phone, masked, code) 三参而非单一「掩码键」:
   腾讯通道下发必须有真实号码(掩码/哈希无法投递);防泄漏由「实现层
   不得记录 phone」约定 + structlog 全局手机号脱敏兜底。
2. 频控计数按「请求」计(含被拒请求)且在限额检查前自增:否则被拒
   请求不烧额度,攻击者可无限试探;同时这是「连发 11 次第 11 次
   42911」脚本化验收在真实时钟下成立的前提。
3. request_code 对 sender 逃逸的非 AppError 异常兜底包成 61000:
   通道故障不得以 5xxxx 内部错误形式稀释告警(TencentSmsSender 自身
   映射为主,此处仅接漏网)。
4. wire 请求模型(SmsSendRequest/SmsVerifyRequest)定义在 sms_login.py
   内(任务文档允许的两选一,未新建 sms_schemas.py)。
2026-08-14 20:04:46 +08:00
..

packages/identity/ — 账号与会话

职责(架构 §4.1):账号、登录、会话、设备、游客迁移、同意授权记录。 不负责:权益判定(归 billing)。

铁律

identity 不得依赖任何其他业务域(架构 §4.2)—— 登录链路不能被业务拖累。 import-linter 契约 identity must not depend on any other business domain 会 在 CI 拦下违规 import。

已实现

  • id_user / id_user_identity / id_consent 表
  • 外部身份 → 内部 user_id 映射(内部主键与外部身份解耦,便于加登录通道)
  • 同意记录写入
  • JWT access token(packages/shared/security.py)

待实现

需求 内容
FR-ACC-01 华为账号登录(UnionID/OpenID)
FR-ACC-04 手机号验证码登录(5 分钟有效、单号限频)
FR-ACC-05 双令牌:id_session + 服务端可撤销的 refresh token
FR-ACC-02/03 游客模式与数据合并(合并必须幂等)
FR-ACC-08 人脸单独同意页(CR-01:必须独立,不得混入总协议)
FR-ACC-09 账号注销:7 日内彻底删除,含 COS 对象(CR-03)
FR-ACC-11 未成年人判定与功能限制(CR-04)
FR-SYS-01 越权防护:所有资源访问校验归属,不能只靠 ID 不可猜

POST /auth/dev-token 只是脚手架,DEV_AUTH_ENABLED=false 时不可用, 生产环境必须关闭。