# iOS 登录流程 —— 总体设计 --- ## 一、核心理解 ``` Apple 登录不是你的 App 登录系统本身。 Apple 只是帮你证明"这个人是谁"。 真正的登录态,要由你的后端发 accessToken / refreshToken。 ``` 最终流程: ``` iOS 调 Apple 登录 → 拿到 Apple identityToken → 发给你的 NestJS 后端 → 后端校验 Apple token → 后端创建 / 查找用户 → 后端生成自己的 accessToken + refreshToken → iOS 存 Keychain → 以后所有接口带 Authorization: Bearer accessToken ``` **开发建议**:先做 `dev-login → /users/me → Keychain → 知识库接口`,Apple 登录随后再接,不要让 Apple 流程卡住后端开发。 --- ## 二、认证系统核心模型 后端登录系统的本质是建立自己的认证体系: ``` users + auth_accounts (支持多 provider:DEV、APPLE) + refresh_tokens (只存 hash,不存明文) + accessToken (短期令牌,JWT) + refreshToken (长期令牌,JWT,可轮换/撤销) + JwtAuthGuard (全局守卫) + /users/me (启动态判定核心接口) ``` Apple 登录只是其中一个 provider。核心是通过 `auth_accounts` 表关联第三方身份与本地用户。 --- ## 三、接口清单 第一版 5 个接口: | 接口 | 用途 | 优先级 | |------|------|--------| | `POST /api/auth/dev-login` | 开发调试登录 | ⭐ 先做 | | `POST /api/auth/refresh` | 刷新登录态 | ⭐ 先做 | | `GET /api/users/me` | 获取当前用户 | ⭐ 先做 | | `POST /api/auth/apple` | Apple 正式登录 | 随后接 | | `POST /api/auth/logout` | 退出登录 | 最后做 | --- ## 四、统一返回格式 登录成功后后端统一返回: ```json { "accessToken": "eyJ...", "refreshToken": "eyJ...", "user": { "id": "user_xxx", "email": "test@zhixi.app", "nickname": "测试用户", "avatarUrl": null, "role": "USER", "status": "ACTIVE", "onboardingCompleted": false } } ``` iOS 拿到后: | 数据 | 存储位置 | 用途 | |------|---------|------| | `accessToken` | 内存 | 接口请求 Authorization Header | | `refreshToken` | Keychain | 恢复登录 | | `user` | AppSession / UserStore | 用户信息展示 | --- ## 五、后端模块结构 ``` src/modules/auth/ ├── auth.controller.ts # 登录/刷新/登出接口 ├── auth.service.ts # 通用登录逻辑(provider 调度) ├── apple-auth.service.ts # Apple identityToken 校验 ├── token.service.ts # JWT 生成/校验 ├── dto/ │ ├── dev-login.dto.ts │ ├── apple-login.dto.ts │ └── refresh-token.dto.ts ├── guards/ │ └── jwt-auth.guard.ts # 全局认证守卫 ├── decorators/ │ └── current-user.decorator.ts # 从 JWT 取用户 └── strategies/ └── jwt.strategy.ts src/modules/users/ ├── users.controller.ts # /users/me ├── users.service.ts └── dto/ ``` --- ## 六、业务接口安全规则 所有业务接口依赖登录体系。**核心规则:不要相信前端传的 `userId`。** ```http GET /api/knowledge-bases Authorization: Bearer accessToken ``` 后端应从 JWT 拿当前用户: ```ts // ✅ 正确:从 token 里取 currentUser.id where: { userId: currentUser.id, deletedAt: null } // ❌ 错误:从请求体取 userId where: { userId: body.userId } ``` 用户资源接口,只相信 JWT 里的 `currentUser.id`,不允许前端传递 `userId` 参数。 --- ## 七、推荐开发顺序 ``` 1. Prisma 建 users / auth_accounts / refresh_tokens 2. TokenService:生成 accessToken / refreshToken 3. dev-login 接口 4. JwtAuthGuard 5. CurrentUser 装饰器 6. /users/me 接口 7. iOS 接 dev-login + Keychain + AppSession 8. 知识库接口全部加 JwtAuthGuard 9. Apple 登录接口 10. refresh 接口 11. logout 接口 ``` --- ## 八、环境变量最小配置 ```env JWT_ACCESS_SECRET=你自己的随机强密钥 JWT_REFRESH_SECRET=你自己的随机强密钥 APPLE_BUNDLE_ID=cloud.longde.AIStudyApp APPLE_ISSUER=https://appleid.apple.com APPLE_JWKS_URL=https://appleid.apple.com/auth/keys ``` --- ## 九、总结 最终一句话:后端登录对接的核心不是"接 Apple 登录按钮",而是先建立自己的认证系统。Apple 登录只是其中一个 provider。先把 `dev-login → token → /users/me → iOS Keychain` 跑通,知识库和学习闭环就不会卡住。