# iOS Auth API Contract > 冻结日期:2026-05-27 | 版本:1.0 | 未经评审不得修改请求/响应字段 ## 1. 基础约定 | 项目 | 值 | |------|-----| | Base URL(生产) | `https://api.longde.cloud` | | Content-Type | `application/json` | | 认证方式 | `Authorization: Bearer ` | | 成功响应格式 | `{ success: true, data: , timestamp: "ISO8601" }` | | 错误响应格式 | `{ success: false, statusCode: , message: "<中文>", errorCode: "<语义码>" }` | ## 2. Token 生命周期 | Token | 有效期 | 存储位置 | |-------|--------|----------| | accessToken (JWT) | 1 小时 | Keychain | | refreshToken (opaque) | 7 天 | Keychain | - refreshToken 是一次性的:每次 `/auth/refresh` 成功后旧的立即吊销,返回新的 - accessToken 过期 → iOS 用 refreshToken 换新,不要重新走 Apple 登录 - refreshToken 过期 → 回到登录页 ## 3. 接口清单 ### 3.1 Apple 登录 ``` POST /auth/apple ``` **请求体:** | 字段 | 类型 | 必需 | 说明 | |------|------|------|------| | identityToken | string | 是 | Apple 返回的 JWT identityToken | | authorizationCode | string | 否 | Apple 返回的授权码(建议传) | | nonce | string | 否 | iOS 生成的原始 nonce(未哈希) | | fullName.givenName | string | 否 | 用户的名 | | fullName.familyName | string | 否 | 用户的姓 | | email | string | 否 | Apple 返回的邮箱 | **成功响应 `data`:** | 字段 | 类型 | 说明 | |------|------|------| | accessToken | string | JWT,含 type: "user" | | refreshToken | string | 96 位十六进制字符串 | | user.id | string | 用户 ID | | user.email | string\|null | 邮箱 | | user.nickname | string\|null | 昵称 | | user.avatarUrl | string\|null | 头像 URL | | user.role | string | 角色 | | user.status | string | 状态 | | user.onboardingCompleted | boolean | 是否完成引导 | **错误:** | errorCode | HTTP | 说明 | |-----------|------|------| | AUTH_INVALID_APPLE_TOKEN | 401 | identityToken 无效、过期或验证失败 | ### 3.2 刷新 Token ``` POST /auth/refresh ``` **请求体:** | 字段 | 类型 | 必需 | |------|------|------| | refreshToken | string | 是 | **成功响应 `data`:** 同登录响应(新 accessToken + 新 refreshToken + user) **错误:** | errorCode | HTTP | 说明 | |-----------|------|------| | AUTH_REFRESH_TOKEN_EXPIRED | 401 | 超过 7 天未使用 | | AUTH_REFRESH_TOKEN_REVOKED | 401 | 已被登出/安全事件撤销 | | AUTH_USER_DISABLED | 401 | 账号被管理员禁用 | | AUTH_USER_DELETED | 401 | 账号已注销 | ### 3.3 获取当前用户 ``` GET /users/me ``` 需要 Bearer token。 **成功响应 `data`:** 用户对象(同登录响应中的 user) **错误:** | errorCode | HTTP | 说明 | |-----------|------|------| | AUTH_UNAUTHORIZED | 401 | 未登录或 token 过期 | | AUTH_USER_DISABLED | 401 | 账号被禁用 | | AUTH_USER_DELETED | 401 | 账号已注销 | | AUTH_WRONG_TOKEN_TYPE | 401 | 使用了 admin token | ### 3.4 登出 ``` POST /auth/logout ``` 需要 Bearer token。 **请求体:** | 字段 | 类型 | 必需 | |------|------|------| | refreshToken | string | 是 | **成功响应:** `{ success: true, message: "已退出登录" }` **错误:** | errorCode | HTTP | 说明 | |-----------|------|------| | AUTH_UNAUTHORIZED | 401 | token 已过期(不影响客户端清本地状态) | ## 4. 完整错误码表 | errorCode | 含义 | iOS 处理策略 | |-----------|------|-------------| | AUTH_INVALID_APPLE_TOKEN | Apple token 验证失败 | 提示用户重试 Apple 登录 | | AUTH_USER_DISABLED | 账号被禁用 | 清空本地 session,显示禁用提示 | | AUTH_USER_DELETED | 账号已注销 | 清空本地 session,回到欢迎页 | | AUTH_REFRESH_TOKEN_EXPIRED | Refresh token 过期 | 清空本地 session,回到登录页 | | AUTH_REFRESH_TOKEN_REVOKED | Refresh token 被撤销 | 清空本地 session,回到登录页 | | AUTH_UNAUTHORIZED | 未认证 | 尝试 refresh,失败则回登录页 | | AUTH_WRONG_TOKEN_TYPE | Token 类型错误 | 清空本地 session,重新登录 | | AUTH_DEV_LOGIN_FORBIDDEN | 生产环境禁用 dev 登录 | 不触发(仅 iOS 不关心) | | VALIDATION_ERROR | 请求参数校验失败 | 检查发送的字段 | | NOT_FOUND | 资源未找到 | 提示用户 | | FORBIDDEN | 权限不足 | 提示用户 | | RATE_LIMITED | 请求过快 | 稍后重试 | | INTERNAL_ERROR | 服务器错误 | 提示用户稍后重试 | ## 5. iOS 实现要点 1. **Token 存储** — 用 Keychain(不是 UserDefaults) 2. **401 自动刷新** — APIClient 拦截 401,用 refreshToken 换新 accessToken,失败则清 session 3. **并发刷新** — 多个请求同时 401 时只发一次 refresh 4. **AppSession 状态** — 维护状态机:`unauthenticated → authenticating → authenticated → refreshing/expired/disabled/deleted` 5. **Apple 登录 nonce** — 用 `SecRandomCopyBytes` 生成,SHA256 后传给 Apple,原始值传给后端 6. **authorizationCode** — 提取并传给后端