180 lines
4.4 KiB
Markdown
Raw Normal View History

# 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 (支持多 providerDEV、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` 跑通,知识库和学习闭环就不会卡住。