180 lines
4.4 KiB
Markdown
180 lines
4.4 KiB
Markdown
|
|
# 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` 跑通,知识库和学习闭环就不会卡住。
|