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)。 偏差说明:无
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 时不可用,
生产环境必须关闭。