WangDL fe608da385 docs: 重构技术设计目录结构 + 更新待完成清单
- 文档从扁平结构迁移至分类目录 (api-server/ios-projects/web-projects/长期规划)
- 更新总待完成清单 (B1-B6 全部完成, I1-I7 全部完成)
- 新增后端实现状态、已实现功能汇总等已完成文档
- 新增 iOS 功能需求清单、架构设计、差距分析等文档
- 清理旧版未维护文档

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 19:08:59 +08:00

173 lines
4.3 KiB
Markdown
Raw 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.

# iOS 登录流程 —— iOS 端集成
---
## 一、iOS 需要的核心组件
```
AuthService ← 调后端登录接口
UserService ← 用户信息管理
TokenStore ← token 存储协议
KeychainTokenStore ← 基于 Keychain 的安全存储实现
AppSession ← 管理当前登录态
```
---
## 二、数据存储策略
| 数据 | 存储位置 | 生命周期 | 原因 |
|------|---------|---------|------|
| `accessToken` | 内存 | App 运行期间 | 短期使用,不需要持久化 |
| `refreshToken` | Keychain | 长期持久化 | 敏感凭证,需安全存储,卸载后也保留 |
| `user` | AppSession / UserStore | App 运行期间 | 用户展示信息 |
---
## 三、App 启动流程
```
App 启动
→ AppSession.checkSession()
→ 从 Keychain 读取 refreshToken
→ 如果没有 refreshToken
→ 进入登录页
→ 如果有 refreshToken
→ 调用 POST /api/auth/refresh
→ 成功
→ 存储新的 accessToken + refreshToken
→ 调用 GET /api/users/me
→ 存储 user 信息
→ 进入主界面
→ 失败
→ 清空 Keychain + 内存 token
→ 进入登录页
```
---
## 四、登录流程
### 开发登录dev-login
```
用户在登录页输入邮箱/昵称
→ AuthService.devLogin(email, nickname)
→ POST /api/auth/dev-login
→ 后端返回 { accessToken, refreshToken, user }
→ refreshToken 存 Keychain
→ accessToken 放内存
→ user 放 AppSession
→ 进入主界面
```
### Apple 登录
```
用户点击 Sign in with Apple
→ iOS 系统弹出 Apple 授权界面
→ 用户授权成功
→ 拿到 identityToken + authorizationCode 等
→ AuthService.appleLogin(identityToken, ...)
→ POST /api/auth/apple
→ 后端验证 Apple token返回 { accessToken, refreshToken, user }
→ refreshToken 存 Keychain
→ accessToken 放内存
→ user 放 AppSession
→ 进入主界面
```
---
## 五、接口请求拦截
所有需要登录的接口都必须携带:
```http
Authorization: Bearer {accessToken}
```
### HTTP Client 封装建议
```
所有请求自动注入 Authorization Header
→ 从 AuthService 获取当前 accessToken
→ 自动添加到请求头
```
### 401 自动处理
```
接口返回 401
→ 调用 POST /api/auth/refresh
→ 成功
→ 更新 accessToken
→ 自动重试原请求
→ 失败
→ 清空 Keychain + 内存数据
→ 跳转登录页
```
**重要**:重试原请求时注意避免无限循环,设置最多重试 1 次。
---
## 六、退出登录
```
用户点击退出登录
→ AuthService.logout()
→ POST /api/auth/logout
Body: { refreshToken: 从 Keychain 取的 refreshToken }
Header: Authorization: Bearer accessToken
→ 后端标记 refreshToken revoked
→ iOS 端:
→ 清除 Keychain 中的 refreshToken
→ 清除内存中的 accessToken
→ 清除 AppSession 中的 user
→ 跳转登录页
```
---
## 七、Token 存储对比UserDefaults vs Keychain
| | UserDefaults | Keychain |
|------|------------|----------|
| 安全性 | 低(明文存储) | 高(系统级加密) |
| 应用卸载后 | 数据被清除 | 可选保留(推荐保留) |
| 备份 | 包含在 iTunes/iCloud 备份中 | 仅加密备份 |
| 适用数据 | 非敏感偏好设置 | 密码、Token 等敏感凭据 |
**结论refreshToken 一定要用 Keychain 存储。**
---
## 八、Session 状态机
```
App 启动
┌─────────────────┐
│ 检查 Keychain │
│ 有 refreshToken? │
└───────┬─────────┘
┌───────┴───────┐
│ 有 │ 无
▼ ▼
┌─────────┐ ┌──────────┐
│ 调 refresh │ │ 进入登录页 │
│ 接口 │ └──────────┘
└─────┬─────┘
┌────┴────┐
│ 成功 │ 失败
▼ ▼
┌────────┐ ┌──────────┐
│ 调 /me │ │ 清空数据 │
│ 进主页 │ │ 进登录页 │
└────────┘ └──────────┘
```