feat(auth): implement user and device authentication

This commit is contained in:
QiuSW
2026-07-26 15:18:48 +08:00
parent c5d3b215ff
commit 49db5b8305
66 changed files with 6216 additions and 271 deletions
+27 -6
View File
@@ -13,10 +13,9 @@
- 分页使用 `limit` 和不透明 `cursor`;MVP `limit` 最大 100。
- 客户端不得根据 HTTP 超时判断操作失败,必须查询资源最终状态。
T-204 管理会话完成前,T-203 的管理 Web 和管理 API 只接受来源地址为 loopback 的
请求,Web 写操作还要求 SameSite Cookie 与表单字段匹配的随机双提交 CSRF token。
该门禁只用于阻止业务路由被提前暴露,不是正式身份认证;`/login`、管理会话和
局域网访问仍由 T-204 实现。
管理 Web/API 使用 ADMIN 服务端会话;App 执行接口使用 BUYER + 设备 Bearer token。
两种身份不能互换。HTTP 明文只允许 loopback 开发监听,非 loopback 服务必须配置
certificate/private key 并直接启用 TLS。
通用错误:
@@ -71,7 +70,18 @@ HTTP 语义:
### 管理 Web 会话
`POST /login` 接受表单账号密码,成功后设置 `HttpOnly`、`Secure`、`SameSite=Lax`
会话 Cookie。`POST /logout` 清除会话。Web 会话不能调用设备执行接口。
会话 Cookie。loopback HTTP 开发时不设置 `Secure`,非 loopback 服务必须直接启用
TLS。管理会话固定 8 小时绝对有效期;`POST /logout` 撤销服务端会话并清除 Cookie。
Web 会话不能调用设备执行接口。
未登录页面请求以 `303` 跳转 `/login?next=...`;`next` 只允许 `/tasks` 及其本站
子路径。未授权管理 API 返回 `401 ADMIN_SESSION_REQUIRED`。Cookie 认证的管理 API
写请求除原 Content-Type/幂等要求外,还必须携带与 CSRF Cookie 匹配的
`X-CSRF-Token`。
`POST /login` 在通过表单和 CSRF 校验、执行 bcrypt 前,按服务端观察到的来源地址
限流。5 分钟内最多 10 次;成功登录清零。超限返回 `429`、`Retry-After` 和通用
中文提示,不暴露账号是否存在。
### `POST /api/v1/auth/token`
@@ -92,7 +102,7 @@ HTTP 语义:
```json
{
"access_token": "opaque-or-jwt-token",
"access_token": "opaque-token-returned-once",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
@@ -109,6 +119,14 @@ HTTP 语义:
密码和设备 token 不得出现在响应、日志或 execution event 中。
T-204 固定使用 256 bit 随机 opaque access token,数据库只保存 SHA-256,固定
1 小时过期。用户必须为有效 `BUYER`,设备必须预授权且启用;未绑定设备在首次成功
登录时原子绑定当前采购员,已绑定其他采购员时拒绝。T-204 不提供设备自助登记、
refresh 或 App logout;Android 安全存储接入属于 T-206。
App token 登录与管理登录使用独立限流 scope,同样为每个来源地址 5 分钟最多 10 次。
超限返回 `429`、`Retry-After` 和稳定错误码 `AUTH_RATE_LIMITED`,`retryable=true`。
## 资产
### `POST /api/v1/assets`
@@ -222,6 +240,9 @@ T-203 成功返回 `201`。使用相同 `Idempotency-Key` 和相同图片内容
- `execution`:step、outcome、错误、`order_submitted`。
- `events` 和 `assets`:有权限的摘要。
T-204 已实现的 `TASK_CREATED`、`TASK_CANCELED` 事件包含可空
`actor_user_id`;新管理操作写入真实 ADMIN 用户 ID,T-203 历史事件返回 `null`。
### `POST /api/v1/tasks/{task_id}/cancel`
管理端取消任务。`PENDING` 可立即取消;执行中只设置取消请求,App 在安全检查点确认