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

4.0 KiB
Raw Blame History

iOS 登录流程 —— 数据库设计


一、users 表

用户主表,存储用户基础信息。

model User {
  id                  String       @id @default(cuid())
  email               String?
  nickname            String?
  avatarUrl           String?
  role                UserRole     @default(USER)
  status              UserStatus   @default(ACTIVE)
  onboardingCompleted Boolean      @default(false)

  authAccounts        AuthAccount[]
  refreshTokens       RefreshToken[]

  createdAt           DateTime     @default(now())
  updatedAt           DateTime     @updatedAt
}

enum UserRole {
  USER
  ADMIN
  SUPER_ADMIN
}

enum UserStatus {
  ACTIVE
  DISABLED
  DELETED
}
字段 类型 说明
id String (cuid) 主键
email String? 邮箱可选Apple 登录首次可能提供)
nickname String? 昵称
avatarUrl String? 头像 URL
role UserRole 角色,默认 USER
status UserStatus 状态,默认 ACTIVE
onboardingCompleted Boolean 是否完成引导,默认 false
authAccounts 关联 一对多关联 auth_accounts
refreshTokens 关联 一对多关联 refresh_tokens

二、auth_accounts 表

记录用户通过什么方式provider登录支持一个用户绑定多个登录方式。

model AuthAccount {
  id             String       @id @default(cuid())
  userId         String
  provider       AuthProvider
  providerUserId String
  email          String?

  user           User         @relation(fields: [userId], references: [id])

  createdAt      DateTime     @default(now())
  updatedAt      DateTime     @updatedAt

  @@unique([provider, providerUserId])
  @@index([userId])
}

enum AuthProvider {
  DEV
  APPLE
}
字段 类型 说明
id String (cuid) 主键
userId String 关联 users 表
provider AuthProvider 登录提供商DEV / APPLE
providerUserId String 提供商侧的用户唯一 ID
email String? 提供商侧邮箱
@@unique([provider, providerUserId]) 约束 同一个提供商的用户唯一

查找逻辑

Apple 登录时:
  provider = APPLE
  providerUserId = identityToken 里校验出来的 sub
  → 如果不存在,创建 User + AuthAccount
  → 如果存在,直接找到对应 User

三、refresh_tokens 表

重要refreshToken 不要明文存数据库,只存 hash。

model RefreshToken {
  id        String    @id @default(cuid())
  userId    String
  tokenHash String
  expiresAt DateTime
  revokedAt DateTime?

  user      User      @relation(fields: [userId], references: [id])

  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt

  @@index([userId])
}
字段 类型 说明
id String (cuid) 主键,同时写入 JWT payload 作为 tokenId
userId String 关联 users 表
tokenHash String refreshToken 的 hash 值SHA-256
expiresAt DateTime 过期时间
revokedAt DateTime? 撤销时间(登出时设置)

刷新时的校验链

1. 解析 refreshToken JWT拿到 userId + tokenId
2. 查 refresh_tokens 表,找到对应记录
3. 对比 tokenHash
4. 确认 revokedAt 为 null未撤销
5. 确认 expiresAt 未过期
6. 签发新的 accessToken可选轮换新的 refreshToken

登出时:将对应记录的 revokedAt 设为当前时间。


四、ER 关系总结

User (1) ──── (N) AuthAccount       一个用户可有多种登录方式
User (1) ──── (N) RefreshToken      一个用户可有多个活跃 refreshToken多设备
  • 用户与登录方式是解耦的:用户是一个独立实体,通过 auth_accounts 关联到具体的第三方身份。
  • 这种设计天然支持未来扩展更多登录方式(如 Google、微信等只需在 AuthProvider 枚举中添加即可。