api-server/docs/ios登录流程-总览.md
WangDL fa69749884 refactor(auth): restructure auth system, align with iOS login flow spec
- Split AuthService into AppleAuthService, TokenService, AuthService
- Add dev-login endpoint (dev-only, disabled in production)
- AppleLoginDto: authorizationCode optional, add userIdentifier/email/fullName/nonce
- Login/refresh responses now include user object
- logout: single-token revoke + JwtAuthGuard protection
- users.repository: switch from in-memory Map to Prisma persistence
- JWT payload includes role, guards attach full user info to request
- Dual JWT secret support (JWT_ACCESS_SECRET / JWT_REFRESH_SECRET)
- Replace jwks-rsa+jsonwebtoken with jose library
- Prisma User model: add role field
- Independent DTO files with @Transform for empty string safety
- Add 5 iOS login flow documentation files
2026-05-13 17:31:50 +08:00

180 lines
4.4 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 登录流程 —— 总体设计
---
## 一、核心理解
```
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` 跑通,知识库和学习闭环就不会卡住。