# 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 │ │ 清空数据 │ │ 进主页 │ │ 进登录页 │ └────────┘ └──────────┘ ```