feat(api): 账户资料与密码安全
This commit is contained in:
+41
-5
@@ -10,8 +10,10 @@
|
||||
"id": "uuid",
|
||||
"email": "owner@example.com",
|
||||
"display_name": null,
|
||||
"avatar_asset_id": null,
|
||||
"email_verified_at": null,
|
||||
"created_at": "2026-09-02T08:00:00Z"
|
||||
"created_at": "2026-09-02T08:00:00Z",
|
||||
"revision": 1
|
||||
},
|
||||
"workspace": {
|
||||
"id": "uuid",
|
||||
@@ -21,7 +23,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
`email` 返回规范化后的地址;密码散列、会话哈希、手机号及任何风控信息永不返回。
|
||||
`email` 返回规范化后的地址;`avatar_asset_id` 是当前头像的素材引用,普通账户响应不返回对象存储 URL。密码散列、会话哈希、手机号及任何风控信息永不返回。
|
||||
|
||||
## 2. 注册
|
||||
|
||||
@@ -50,7 +52,7 @@
|
||||
"data": {
|
||||
"access_token": "eyJ…",
|
||||
"access_token_expires_in": 900,
|
||||
"user": { "id": "uuid", "email": "owner@example.com", "display_name": "Joey", "email_verified_at": null, "created_at": "2026-09-02T08:00:00Z" },
|
||||
"user": { "id": "uuid", "email": "owner@example.com", "display_name": "Joey", "avatar_asset_id": null, "email_verified_at": null, "created_at": "2026-09-02T08:00:00Z", "revision": 1 },
|
||||
"workspace": { "id": "uuid", "name": "Joey 的工作空间", "role": "owner" }
|
||||
}
|
||||
}
|
||||
@@ -86,7 +88,41 @@
|
||||
|
||||
要求 Bearer access token;撤销当前 refresh session、清除 refresh cookie,返回 `204 No Content`。首期不提供“退出所有设备”。
|
||||
|
||||
## 5. 当前用户与初始页头数据
|
||||
## 5. 修改账户资料
|
||||
|
||||
`PATCH /api/auth/me`
|
||||
|
||||
Headers:`If-Match: "{revision}"` 与 `Idempotency-Key: {uuid}` 必填。
|
||||
|
||||
```json
|
||||
{ "display_name": "Joey", "avatar_asset_id": "uuid" }
|
||||
```
|
||||
|
||||
两个字段至少提交一个;传 `null` 可清除对应资料。成功返回 `200` 与更新后的 `user` 资源,`revision` 加一。`avatar_asset_id` 必须是当前工作空间中已完成素材校验的图片资产;接口不接受 URL、对象存储 key 或 base64 内容。版本过期返回 `409 VERSION_CONFLICT`,相同幂等键遵循统一重放规则。
|
||||
|
||||
头像上传复用 `POST /api/media/upload-intents` 的预签名直传和完成校验流程,并使用 `purpose: "user_avatar"`;在素材模块实现前,头像只能保持 `null`,不能以 base64 上传作为替代通道。
|
||||
|
||||
## 6. 修改密码
|
||||
|
||||
`POST /api/auth/change-password`
|
||||
|
||||
```json
|
||||
{
|
||||
"old_password": "old-strong-password",
|
||||
"password": "new-strong-password",
|
||||
"password_confirmation": "new-strong-password"
|
||||
}
|
||||
```
|
||||
|
||||
此接口要求 Bearer access token,并按来源 IP 和当前用户双维度限流。服务端在一个事务内锁定当前会话和用户、校验旧密码、更新密码散列、撤销该用户全部旧 session,并创建新的当前 session。成功返回 `200`、新的 `HttpOnly` refresh cookie 和:
|
||||
|
||||
```json
|
||||
{ "data": { "access_token": "eyJ…", "access_token_expires_in": 900 } }
|
||||
```
|
||||
|
||||
旧 access token 和其他设备的 session 会立即失效。此接口不使用 `Idempotency-Key`:密码变更及 session 轮换不能安全地将 access token 持久化为幂等回放响应;客户端收到网络中断后应以新旧密码重新登录或刷新会话,不得盲目自动重试。
|
||||
|
||||
## 7. 当前用户与初始页头数据
|
||||
|
||||
`GET /api/auth/me`
|
||||
|
||||
@@ -95,7 +131,7 @@
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"user": { "id": "uuid", "email": "owner@example.com", "display_name": "Joey", "email_verified_at": null },
|
||||
"user": { "id": "uuid", "email": "owner@example.com", "display_name": "Joey", "avatar_asset_id": null, "email_verified_at": null, "revision": 1 },
|
||||
"workspace": { "id": "uuid", "name": "Joey 的工作空间", "role": "owner" },
|
||||
"platforms": [{ "id": "uuid", "code": "OZON", "name": "Ozon" }],
|
||||
"suggested_context": {
|
||||
|
||||
@@ -100,6 +100,7 @@ X-Atlas-Platform-Id: 57ad…-uuid
|
||||
## 5. 写操作的幂等、并发和异步
|
||||
|
||||
- 创建店铺、上传意图、删除水印模板等可重试写操作应携带 `Idempotency-Key: <UUID>`。服务端按“当前用户 + 工作空间 + HTTP 方法 + 规范化实际路径 + key”保存至少 24 小时(首期默认 48 小时);请求摘要保存为服务端 HMAC,而非明文请求体。相同键、相同请求返回已保存响应;相同键、不同请求返回 `409 IDEMPOTENCY_KEY_REUSED`;原请求仍在执行返回 `409 IDEMPOTENCY_REQUEST_IN_PROGRESS`。
|
||||
- `PATCH /api/auth/me` 同样要求幂等键。`POST /api/auth/change-password` 是例外:其成功响应包含新 access token,不能将该 token 持久化到幂等回放表;客户端不得自动重试此操作。
|
||||
- 更新可编辑资源时,读取响应携带 `revision`;客户端在 `PATCH`/`PUT` 中提交 `If-Match: "<revision>"`。版本已变化返回 `409 VERSION_CONFLICT` 和最新 `current_revision` 摘要。`revision` 是并发控制版本;不要把水印的渲染 `current_version` 当作它。
|
||||
- 耗时动作(店铺凭据验证、仓库同步、媒体处理)先返回 `202 Accepted`,并在资源中返回 `operation`。客户端轮询 `GET /api/operations/{operation_id}`;后续可追加 SSE,不改变资源接口。
|
||||
- 所有启动异步工作的业务写入,必须在同一 PostgreSQL 事务中写入业务资源/`operation` 和 `outbox_events`;独立 Dispatcher 再投递 BullMQ。BullMQ 和 Redis 不得作为任务存在或最终业务结果的唯一事实。
|
||||
|
||||
Reference in New Issue
Block a user