Files
atlas-seller-kit/docs/api/auth.md
2026-09-03 16:56:20 +08:00

146 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 账户与会话 API
> 首期只支持邮箱 + 密码。邮箱验证、密码找回、手机号、短信登录、第三方登录和 MFA 均不在本契约中。
## 1. 数据形状
```json
{
"user": {
"id": "uuid",
"email": "owner@example.com",
"display_name": null,
"avatar_asset_id": null,
"email_verified_at": null,
"created_at": "2026-09-02T08:00:00Z",
"revision": 1
},
"workspace": {
"id": "uuid",
"name": "owner 的工作空间",
"role": "owner"
}
}
```
`email` 返回规范化后的地址;`avatar_asset_id` 是当前头像的素材引用,普通账户响应不返回对象存储 URL。密码散列、会话哈希、手机号及任何风控信息永不返回。
## 2. 注册
`POST /api/auth/register`
```json
{
"email": "owner@example.com",
"password": "a-strong-password",
"password_confirmation": "a-strong-password",
"display_name": "Joey"
}
```
规则:
- `email` 去除首尾空格后以不区分大小写的形式判重;必须满足基础邮箱格式。
- `password` 和确认值一致;最小长度与复杂度仍待认证安全规则确认,服务端将作为唯一校验方,前端只能展示同一规则而不能自行放宽。
- `display_name` 可选,最大 80 个字符。
- 成功时在同一事务创建 `user`、个人 `workspace` 和 `owner` membership,并创建登录会话。
成功返回 `201 Created`、`Set-Cookie` refresh token 和:
```json
{
"data": {
"access_token": "eyJ…",
"access_token_expires_in": 900,
"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" }
}
}
```
重复邮箱返回 `409 EMAIL_ALREADY_REGISTERED`。首期不通过“邮箱不存在/密码错误”以外的差异化响应泄露登录状态。
## 3. 登录
`POST /api/auth/login`
```json
{ "email": "owner@example.com", "password": "a-strong-password" }
```
成功响应与注册相同,刷新 token 写入新的 `HttpOnly` cookie。失败统一返回 `401 INVALID_CREDENTIALS`;禁用账户返回 `403 ACCOUNT_DISABLED`。接口应按 IP 与邮箱摘要双维度限流,但不保存明文密码或将其记入日志。
成功返回 `200 OK`、`Set-Cookie` refresh token 及上述响应体。
## 4. 刷新与退出
`POST /api/auth/refresh`
请求不需要 body,浏览器自动携带 refresh cookie。服务端轮换 refresh token、撤销旧 session 并以 `200 OK` 返回新的短期 access token:
```json
{ "data": { "access_token": "eyJ…", "access_token_expires_in": 900 } }
```
无效、过期或已撤销 refresh token 返回 `401 SESSION_EXPIRED`,并清除 refresh cookie。
`POST /api/auth/logout`
要求 Bearer access token;撤销当前 refresh session、清除 refresh cookie,返回 `204 No Content`。首期不提供“退出所有设备”。
## 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`
返回已登录用户、首期唯一工作空间、可用平台及当前页头建议值:
```json
{
"data": {
"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": {
"platform_id": "uuid",
"default_store": null
}
}
}
```
首期建议按平台配置顺序优先 Ozon;若该平台有默认店铺,`default_store` 返回店铺摘要,否则为 `null`。这只是页头初始建议,不在服务端建立“用户全局已选平台”状态;客户端切换平台后,在后续平台范围请求传 `X-Atlas-Platform-Id`。