Files
meida_backend/packages/identity
xsl 6c77ff4989 feat(identity): Huawei Account Kit login via OIDC JWKS verification
POST /auth/huawei:JWKS 验签(kid 缓存/轮换)+ claims 严格校验 +
UnionID 映射 + T4 双令牌签发(FR-ACC-01;真实联调待 AGC 配置)。

- packages/identity/huawei.py(新建):HuaweiIdTokenVerifier——RS256 验签,
  JWKS 内存缓存(TTL 可配 + 单调钟;kid 未命中强制刷新一次重试,锁内用
  拉取代数防止强制刷新被新鲜缓存短路);aud/iss/exp/iat 全查,audience
  空配置直接拒绝而非跳过;union_id 缺失拒绝(降级 open_id 策略不做,
  留联调期决定);错误映射 40102/40101/60000,无新错误码。
  HuaweiLoginRequest/HuaweiClaims 一并定义于此,未动 schemas.py。
- apps/api/routers/auth.py:追加 /huawei 端点;get_huawei_verifier 依赖
  建于路由模块内(缓存到 app.state,可预注入替换),未动 deps.py;
  复用 T4 的 get_or_create_by_external_identity + issue_session +
  TokenPairResponse 与既有 _token_pair/_access_token。
- tests/unit/test_huawei_verifier.py:cryptography 自造 RSA + 本地 JWKS
  (零外网),19 例覆盖合法 claims/错误签名/过期/aud/iss/iat 缺失/
  audience 未配置/union_id 缺失/HS256 混淆/JWKS 拉取失败/kid 轮换/缓存
  TTL。
- tests/integration/test_auth_huawei.py:FakeFetcher 预注入 app.state,
  真实 PG 验证首次建用户 + 双令牌、同 union_id 复登同 user_id、新 access
  调 /quota、refresh 可轮换、伪造 token 40102。

检查:ruff/format/mypy(T6 列表)/lint-imports 全绿;单测 257 passed
(基线 238 + 新增 19);集成 18 passed(含新增 2)。

偏差说明:无
2026-08-14 19:59:15 +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 时不可用, 生产环境必须关闭。