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
xsl
140a63effa
feat(identity): refresh token rotation with server-side revocable sessions
...
id_session 落地:opaque refresh(token_urlsafe(48))+ sha256 哈希存储 +
一次性轮换(旧行撤销与新行同一事务)+ logout 幂等撤销 + 已撤销重放检测
告警(V1 不做家族连坐);错误码 40103/40104/40105 接入。新增 POST
/auth/refresh、POST /auth/logout;dev-token 扩展为双令牌,旧字段
access_token/token_type/expires_in/user_id 原名保留,新增
refresh_token/refresh_expires_in(smoke.sh 不受影响)。
测试:tests/unit/test_refresh_tokens.py 覆盖 token 长度/字符域/唯一性、
哈希稳定性与不可逆(7 例,不连网不连库);tests/integration/
test_auth_refresh.py 覆盖轮换后新 access 可调 /quota、旧 refresh 二次
使用 40105、logout 后失效 40105、伪造 40103、TTL=0 过期 40104(5 例)。
门禁全绿:ruff check/format、mypy 两段、lint-imports 4 契约、
单测 176 通过、集成 8 通过。
偏差说明:1) SessionIssued 较任务文档字段清单增加 user_id ——
/auth/refresh 换发 access JWT 必须知道用户,opaque refresh 本身不携带
信息,只能随签发结果带回;2) 过期分支「顺手落库 revoked=true」在 HTTP
路径会随 401 的统一回滚一起丢失(仅事务内标记,已注释说明,不影响判定
语义);3) repo 撤销用 SELECT FOR UPDATE + ORM 变更而非 UPDATE
rowcount —— 对齐 billing.repo 现行模式,且 rowcount 在 mypy 下类型
不可用。
2026-08-14 16:21:52 +08:00
xsl
7c67506474
feat(domains): identity, billing, task services and domain placeholders
...
Billing implements reserve -> commit -> refund against bl_quota and bl_ledger
with row-level locking and idempotency keys; the refund commits on its own
transaction so a failed request cannot silently keep a user's quota. Task
implements the unified task centre over the state machine. Identity issues and
resolves users. Remaining domains are placeholders whose READMEs state what
belongs there and what must not.
2026-08-14 00:26:39 +08:00