b359bbe3bf
pytest / test (push) Successful in 54s
- roadmap.md: M1 (DB consolidation) -> M2 (React SPA) -> M3 (token/mobile) - docs/design/: agent-pipeline design docs with atomic tasks for M1-M3 - CLAUDE.md: workflow, doc map, commit conventions, review-notes briefing flow - .gitignore: ignore local review-notes/
6.6 KiB
6.6 KiB
M3 — Token 鉴权与移动端(远期试水)
阅读前提:先读
README.md。M3 依赖 M2(已有/apiJSON 契约与 session 鉴权)。定位:远期、低投入、探索性。React Native 部分主要是"没做过、试试水"。范围可能收缩——其中token 鉴权 + ingestion 端点收口是有持久价值的安全改进,应优先;RN app 是加分项。Orchestrator 可只取前半。
1. 目标
- 引入 bearer token 鉴权,让非浏览器客户端(移动端、设备脚本)能安全访问。
- 把 M2 暂时维持裸奔的 ingestion 端点(
POST /location/record、POST /poo/record)收口到 token 鉴权下。 - 做一个 React Native 移动端,用类 OAuth 流程拿 token 后消费现有
/api。
2. 现状(M2 完成后)
/api/*走 session cookie +X-CSRF-Token。app/services/auth.py有 server-side session(auth_sessions表,token_hash 存储)。POST /location/record、POST /poo/record仍无鉴权(设备/脚本裸调用)。
3. 目标架构
3.1 Token 模型
- 新表
auth_tokens:id、user_id、token_hash(仅存哈希)、label(设备名)、created_at、expires_at(可空=长期)、revoked_at。 - bearer 校验:
Authorization: Bearer <token>→ 哈希比对auth_tokens→ 命中且未撤销未过期则认定身份。
3.2 类 OAuth 签发流程(无第三方的 Authorization Code 简化版)
- 移动端在内置浏览器打开
/authorize?...。 - 用户账号密码登录(走现有 session),页面展示"授权此设备"。
- 批准后服务端生成一次性 authorization code,重定向到 app 深链
homeautomation://callback?code=...。 - app 用 code 调
POST /api/auth/token换取 bearer token 并存本地。
简化兜底:批准页直接展示一次性 token 由 app 捕获。优先实现重定向 + code 交换的正规版。
3.3 统一鉴权依赖
/api的数据/CRUD 端点接受session cookie 或 bearer两者之一(同一套端点同时服务 Web 与移动端)。- ingestion 端点(location/poo record)改为要求 bearer。
3.4 React Native
- Expo + TypeScript,复用 M2 的 OpenAPI 类型化 client(共享契约)。
- 内置浏览器走 §3.2 流程拿 token;之后所有请求带
Authorization: Bearer。
4. 迁移注意(重要)
- ingestion 端点一旦要求 bearer,现有调用方(HA/设备脚本)必须先配置 token,否则记录会中断。
- 上线顺序:先签发 token 能力(T01–T02)→ 给现有设备配 token → 再对 ingestion 端点强制 bearer(T03),避免断流。可设一个过渡开关或灰度。
5. 任务依赖图
M3-T01 token 模型 + 迁移
└─► M3-T02 签发流程(authorize + code 交换)
└─► M3-T03 统一鉴权依赖 + ingestion 端点收口(含过渡开关)
├─► M3-T04 Web 端 token 管理 UI(列出/撤销设备)
└─► M3-T05 React Native app(试水)
└─► M3-T06 文档收尾
6. 原子任务(任务卡)
M3-T01 — token 数据模型 + Alembic 迁移
- Status:
todo· Depends: none(M2 完成后) - Files:
create app/models/token.py、alembic_app/versions/<new>_auth_tokens.py;modify app/models/__init__.py;create tests/test_token_model.py - Acceptance:
- 迁移在全新库 upgrade 后建出
auth_tokens表;downgrade 可回滚。 - token 仅以哈希存储(与
auth_sessions同等强度),明文不入库。 - 校验闸门全绿。
- 迁移在全新库 upgrade 后建出
- Reviewer: 哈希算法/长度与现有 session token 一致;
expires_at可空语义明确。
M3-T02 — 签发流程:authorize 页 + code 交换端点
- Status:
todo· Depends: M3-T01 - Files:
create app/api/routes/api/token.py、app/schemas/token.py;前端/authorize页(M2 SPA 内);create tests/test_api_token.py - Acceptance:
- 登录用户在
/authorize批准后得到一次性 code;POST /api/auth/token用 code 换取 bearer,code 一次性且短时效。 - 未登录访问
/authorize跳登录;无效/过期 code 换取失败。 - 返回的 bearer 仅此一次明文出现,库中只存哈希。
- 校验闸门全绿。
- 登录用户在
- Reviewer: code 一次性、绑定用户、短 TTL;深链 redirect 白名单校验,防开放重定向。
M3-T03 — 统一鉴权依赖 + ingestion 端点收口
- Status:
todo· Depends: M3-T02 - Files:
modify app/dependencies.py(新增"cookie 或 bearer"统一身份依赖);modify app/api/routes/location.py、poo.py(要求 bearer,带过渡开关);modify tests - Acceptance:
/api数据/CRUD 端点用合法 bearer 可访问(等价于 session)。- ingestion 端点:带合法 bearer 通过,缺/错 token 在强制模式下 401;过渡开关可临时放行(默认关)。
- 撤销的 token 立即失效。
- 校验闸门全绿。
- Reviewer: 过渡开关默认安全(强制);bearer 与 session 两路鉴权不产生绕过;ingestion 行为变更有测试覆盖。
M3-T04 — Web 端 token 管理 UI
- Status:
todo· Depends: M3-T03 - Acceptance: 在 SPA 内可列出已签发设备 token(label/创建时间/最近使用)、可撤销;撤销后该 token 立即失效;前端闸门全绿。
M3-T05 — React Native app(试水)
- Status:
todo· Depends: M3-T03 ·[experimental] - Files:
create mobile/(Expo + TS,复用 OpenAPI 类型化 client) - Acceptance:
- 内置浏览器走签发流程拿到 token 并安全存储(Keychain/Keystore)。
- 至少跑通:登录拿 token → 拉取一类数据展示 → 记一条 ingestion。
npm run lint/typecheck/build(或 Expo 等价) 全绿。
- Reviewer: token 存安全存储而非明文;client 基于共享 OpenAPI 类型。
M3-T06 — 文档收尾
- Status:
todo· Depends: M3-T05 - Acceptance: README/architecture 增 token 鉴权与移动端说明;roadmap 勾选 M3;
openapi/同步。
7. 里程碑完成定义(DoD)
- 存在 bearer token 鉴权与签发流程;token 仅哈希存储、可撤销。
- ingestion 端点已收口到 bearer(过渡完成后强制)。
/api同时支持 session 与 bearer。- (加分)React Native app 能拿 token 并消费
/api。 - 后端 + 前端 + 移动端各自校验闸门全绿,
openapi/入库。
提醒:本里程碑探索性强,T05 可作为独立试水随时叫停,不影响 T01–T04 带来的安全收口价值。