用户认证系统.md 22 KB

用户认证系统

本文引用的文件

  • server/src/modules/auth/auth.controller.ts
  • server/src/modules/auth/auth.service.ts
  • server/src/middleware/auth.ts
  • server/src/config/index.ts
  • server/src/types/index.ts
  • server/src/models/index.ts
  • server/prisma/schema.prisma
  • server/src/middleware/errorHandler.ts
  • server/src/middleware/security.ts
  • server/src/middleware/rate-limiter.ts
  • server/src/app.ts
  • deploy-package/server/modules/auth/auth.controller.js
  • deploy-package/server/modules/auth/auth.service.js

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本技术文档面向“用户认证系统”,围绕手机号登录流程、JWT 令牌生成与验证机制、用户权限控制策略进行深入解析;同时覆盖认证中间件实现原理、Token 刷新机制与会话管理策略、用户注册流程、登录验证逻辑、密码加密存储、头像上传管理等能力,并提供完整的 API 接口文档、错误码说明、用户状态与权限分级、安全防护措施、常见问题解决方案与性能优化建议。

项目结构

认证子系统主要由以下层次构成:

  • 控制层:处理 HTTP 请求与响应,负责参数校验、调用服务层并返回统一格式结果
  • 服务层:封装业务逻辑,如短信验证码生成与校验、JWT 令牌签发、用户注册与登录、用户信息读取与更新
  • 中间件层:认证中间件、可选认证中间件、安全中间件、限流中间件、错误处理中间件
  • 配置层:JWT 秘钥、过期时间、上传目录大小等全局配置
  • 数据层:Prisma 客户端与数据库模型定义(用户表等)

    graph TB
    subgraph "应用入口"
    APP["应用启动(app.ts)"]
    end
    subgraph "中间件层"
    ERR["错误处理(errorHandler.ts)"]
    SEC["安全中间件(security.ts)"]
    RL["限流中间件(rate-limiter.ts)"]
    AUTHMW["认证中间件(auth.ts)"]
    end
    subgraph "认证模块"
    CTRL["控制器(auth.controller.ts)"]
    SVC["服务(auth.service.ts)"]
    CFG["配置(config.ts)"]
    TYPES["类型(types.ts)"]
    MODELS["模型(models/index.ts)"]
    PRISMA["数据库(schema.prisma)"]
    end
    APP --> ERR
    APP --> SEC
    APP --> RL
    APP --> AUTHMW
    APP --> CTRL
    CTRL --> SVC
    SVC --> MODELS
    MODELS --> PRISMA
    SVC --> CFG
    AUTHMW --> CFG
    AUTHMW --> TYPES
    

图表来源

  • server/src/app.ts:1-194
  • server/src/middleware/errorHandler.ts:1-67
  • server/src/middleware/security.ts:1-154
  • server/src/middleware/rate-limiter.ts:1-120
  • server/src/middleware/auth.ts:1-81
  • server/src/modules/auth/auth.controller.ts:1-94
  • server/src/modules/auth/auth.service.ts:1-115
  • server/src/config/index.ts:1-117
  • server/src/types/index.ts:1-124
  • server/src/models/index.ts:1-15
  • server/prisma/schema.prisma:1-472

章节来源

  • server/src/app.ts:1-194
  • server/src/modules/auth/auth.controller.ts:1-94
  • server/src/modules/auth/auth.service.ts:1-115

核心组件

  • 认证控制器:提供发送验证码、手机号登录、获取用户信息、更新用户信息等接口
  • 认证服务:封装验证码生成/校验、JWT 签发、用户注册/登录、用户信息查询
  • 认证中间件:校验 Authorization 头与 JWT 有效性,注入用户上下文
  • 安全中间件:XSS/SQL 注入防护与敏感数据脱敏
  • 限流中间件:基于内存或 Redis 的限流策略,针对不同接口维度进行配额控制
  • 错误处理中间件:统一捕获异常并返回标准化错误响应
  • 配置中心:集中管理 JWT 秘钥、过期时间、上传大小等
  • 类型系统:统一 JwtPayload、用户信息结构、会员配额等类型定义
  • 数据模型:基于 Prisma 的用户表结构及索引

章节来源

  • server/src/modules/auth/auth.controller.ts:1-94
  • server/src/modules/auth/auth.service.ts:1-115
  • server/src/middleware/auth.ts:1-81
  • server/src/middleware/security.ts:1-154
  • server/src/middleware/rate-limiter.ts:1-120
  • server/src/middleware/errorHandler.ts:1-67
  • server/src/config/index.ts:1-117
  • server/src/types/index.ts:1-124
  • server/src/models/index.ts:1-15
  • server/prisma/schema.prisma:1-472

架构总览

认证系统采用分层架构,请求从应用入口进入,依次经过中间件链路(错误处理、安全、限流),再由认证控制器接收,调用认证服务执行业务逻辑,最终通过 Prisma 访问数据库。

sequenceDiagram
participant C as "客户端"
participant A as "应用(app.ts)"
participant M as "中间件链"
participant R as "认证路由(auth.controller)"
participant S as "认证服务(auth.service)"
participant P as "Prisma(models)"
participant D as "MySQL(schema)"
C->>A : "HTTP 请求"
A->>M : "中间件处理"
M->>R : "路由转发"
R->>S : "调用业务方法"
S->>P : "查询/创建用户"
P->>D : "执行 SQL"
D-->>P : "返回结果"
P-->>S : "用户数据"
S-->>R : "登录结果(含token)"
R-->>C : "统一响应"

图表来源

  • server/src/app.ts:1-194
  • server/src/modules/auth/auth.controller.ts:1-94
  • server/src/modules/auth/auth.service.ts:1-115
  • server/src/models/index.ts:1-15
  • server/prisma/schema.prisma:1-472

详细组件分析

手机号登录流程

  • 参数校验:手机号格式校验
  • 验证码校验:开发环境可跳过,生产环境需校验验证码有效期与一致性
  • 用户查找/创建:按手机号查找,不存在则创建默认用户
  • JWT 签发:生成带用户标识与手机号的令牌,设置过期时间
  • 返回结果:包含 token 与用户信息

    flowchart TD
    Start(["开始"]) --> Validate["校验手机号格式"]
    Validate --> PhoneValid{"格式正确?"}
    PhoneValid -- "否" --> ErrFormat["抛出参数错误"]
    PhoneValid -- "是" --> DevCheck["开发环境免密登录?"]
    DevCheck --> |是| SkipVerify["跳过验证码校验"]
    DevCheck --> |否| VerifyCode["校验验证码(有效期/一致性)"]
    VerifyCode --> CodeOK{"验证码有效?"}
    CodeOK -- "否" --> ErrCode["抛出验证码错误"]
    CodeOK -- "是" --> FindOrCreate["查找或创建用户"]
    FindOrCreate --> CreateUser["创建默认用户(昵称/头像/等级)"]
    CreateUser --> GenToken["生成JWT(7天过期)"]
    VerifyCode --> GenToken
    SkipVerify --> GenToken
    GenToken --> Done(["返回token+用户信息"])
    ErrFormat --> Done
    ErrCode --> Done
    

图表来源

  • server/src/modules/auth/auth.controller.ts:32-52
  • server/src/modules/auth/auth.service.ts:44-97

章节来源

  • server/src/modules/auth/auth.controller.ts:32-52
  • server/src/modules/auth/auth.service.ts:44-97

JWT 令牌生成与验证机制

  • 生成:payload 包含 userId、phone,使用固定秘钥与 7 天过期时间
  • 验证:从 Authorization 头解析 Bearer Token,使用相同秘钥验证签名与有效期
  • 开发模式:可通过环境变量开关跳过认证,便于联调

    sequenceDiagram
    participant S as "服务(auth.service)"
    participant J as "JWT库"
    participant MW as "中间件(auth.ts)"
    participant CL as "客户端"
    CL->>S : "登录(手机号+验证码)"
    S->>J : "sign(payload, secret, {expiresIn})"
    J-->>S : "token"
    S-->>CL : "返回token"
    CL->>MW : "携带Authorization : Bearer token"
    MW->>J : "verify(token, secret)"
    J-->>MW : "payload(含userId/phone)"
    MW-->>CL : "放行(注入ctx.state.user)"
    

图表来源

  • server/src/modules/auth/auth.service.ts:34-41
  • server/src/middleware/auth.ts:7-49
  • server/src/config/index.ts:77-81

章节来源

  • server/src/modules/auth/auth.service.ts:34-41
  • server/src/middleware/auth.ts:7-49
  • server/src/config/index.ts:77-81

认证中间件实现原理

  • 支持强制认证与可选认证两种模式
  • 强制认证:必须携带合法 Bearer Token,否则抛出未授权错误
  • 可选认证:若携带非法 Token,则回退为测试用户上下文
  • 开发模式:可通过环境变量开关跳过认证

    flowchart TD
    Enter(["进入中间件"]) --> CheckAuth["读取Authorization头"]
    CheckAuth --> HasHeader{"存在且格式正确?"}
    HasHeader -- "否" --> Optional{"是否可选认证?"}
    HasHeader -- "是" --> Parse["解析Bearer token"]
    Parse --> Verify["验证JWT(签名/过期)"]
    Verify --> Valid{"有效?"}
    Valid -- "是" --> Inject["注入ctx.state.user"]
    Valid -- "否" --> Optional
    Optional --> |可选| TestUser["注入测试用户(超级VIP)"]
    Optional --> |强制| Err["抛出未授权错误"]
    Inject --> Next["继续后续处理"]
    TestUser --> Next
    Err --> End(["结束"])
    Next --> End
    

图表来源

  • server/src/middleware/auth.ts:51-81
  • server/src/middleware/auth.ts:7-49

章节来源

  • server/src/middleware/auth.ts:51-81
  • server/src/middleware/auth.ts:7-49

Token 刷新机制与会话管理策略

  • 当前实现未提供 Token 刷新接口,JWT 默认 7 天过期
  • 建议策略:
    • 引入 Refresh Token:登录成功返回 Access Token 与 Refresh Token
    • Access Token 短期有效(如 15 分钟),Refresh Token 长期有效(如 7 天)
    • 刷新接口:使用 Refresh Token 换取新的 Access Token
    • 会话管理:服务端记录 Refresh Token 并支持撤销(黑名单/白名单)
    • 安全增强:刷新时校验设备指纹、IP 地址变化触发二次校验

章节来源

  • server/src/modules/auth/auth.service.ts:34-41
  • server/src/config/index.ts:77-81

用户注册流程

  • 若手机号对应的用户不存在,则创建默认用户(昵称、头像、会员等级、用量统计等字段初始化)
  • 新用户标记为“isNewUser”返回给前端

    flowchart TD
    Start(["开始"]) --> FindUser["按手机号查找用户"]
    FindUser --> Exists{"是否存在?"}
    Exists -- "是" --> ReturnUser["返回现有用户"]
    Exists -- "否" --> Create["创建默认用户(昵称/头像/等级)"]
    Create --> ReturnUser
    ReturnUser --> End(["结束"])
    

图表来源

  • server/src/modules/auth/auth.service.ts:66-82

章节来源

  • server/src/modules/auth/auth.service.ts:66-82

登录验证逻辑

  • 手机号格式校验
  • 验证码校验(开发环境可跳过)
  • 用户查找/创建
  • JWT 签发
  • 统一响应包装

章节来源

  • server/src/modules/auth/auth.controller.ts:32-52
  • server/src/modules/auth/auth.service.ts:44-97

密码加密存储

  • 当前系统采用手机号登录,未涉及明文密码存储
  • 若引入账号密码体系,建议:
    • 使用强哈希算法(如 bcrypt、scrypt、argon2)存储密码
    • 为每个用户生成唯一盐值
    • 定期轮换密钥与哈希参数

章节来源

  • server/src/modules/auth/auth.service.ts:11-32

头像上传管理

  • 上传目录:由配置中心统一管理
  • 上传大小限制:50MB(配置项)
  • 建议:
    • 对上传内容进行类型与大小校验
    • 使用对象存储(OSS)替代本地磁盘
    • 对头像进行缩略图生成与 CDN 加速

章节来源

  • server/src/config/index.ts:113-117
  • server/src/app.ts:76-83

用户权限控制策略

  • 会员等级:0(免费)、1(月度)、2(年度)
  • 会员配额:每日生成次数、单次字数上限
  • 免费用户:较低配额
  • 月度/年度用户:更高配额或无限制
  • 限流策略:按用户等级差异化限流

章节来源

  • server/src/types/index.ts:18-124
  • server/src/middleware/rate-limiter.ts:106-110

API 接口文档

  • 发送验证码

    • 方法与路径:POST /api/auth/send-code
    • 请求参数:
    • phone: string(必填,手机号格式校验)
    • 响应:
    • code: number(0 表示成功)
    • message: string
    • data: { phone, code }
    • 错误码:400(参数错误)
  • 手机号登录

    • 方法与路径:POST /api/auth/login
    • 请求参数:
    • phone: string(必填)
    • code: string(非必填;开发环境可为空或特定值跳过校验)
    • 响应:
    • code: number(0 表示成功)
    • message: string
    • data: { token, user: { id, phone, nickname, avatar, memberLevel, isNewUser } }
    • 错误码:400(参数错误)、401(验证码错误或过期)
  • 获取用户信息

    • 方法与路径:GET /api/auth/user-info
    • 请求头:Authorization: Bearer
    • 响应:
    • code: number(0 表示成功)
    • message: string
    • data: { id, phone, nickname, avatar, memberLevel, memberExpireAt, dailyUsage }
    • 错误码:401(未授权)、404(用户不存在)
  • 更新用户信息

    • 方法与路径:PUT /api/auth/user-info
    • 请求头:Authorization: Bearer
    • 请求参数:nickname: string(可选)、avatar: string(可选)
    • 响应:
    • code: number(0 表示成功)
    • message: string
    • data: { nickname, avatar }
    • 错误码:400(用户不存在)、401(未授权)
  • 章节来源

    • server/src/modules/auth/auth.controller.ts:10-92
    • server/src/modules/auth/auth.service.ts:99-115

    依赖关系分析

    classDiagram
    class AuthController {
    +sendCode()
    +login()
    +getUserInfo()
    +updateUserInfo()
    }
    class AuthService {
    +generateSmsCode()
    +verifySmsCode()
    +generateToken()
    +loginWithPhone()
    +getUserInfo()
    }
    class AuthMiddleware {
    +authMiddleware()
    +optionalAuth()
    }
    class ErrorHandler {
    +errorHandler()
    }
    class Security {
    +xssProtection()
    +sqlInjectionProtection()
    +sensitiveDataMasking()
    }
    class RateLimiter {
    +createRateLimiter()
    +apiRateLimiter()
    +loginRateLimiter()
    +smsRateLimiter()
    +ttsRateLimiter()
    +uploadRateLimiter()
    }
    class Config {
    +jwt.secret
    +jwt.expiresIn
    +upload.maxSize
    }
    class Types {
    +JwtPayload
    +MemberLevel
    +ApiResponse
    }
    class Prisma {
    +User
    }
    AuthController --> AuthService : "调用"
    AuthController --> AuthMiddleware : "使用"
    AuthController --> ErrorHandler : "使用"
    AuthController --> Config : "读取"
    AuthService --> Prisma : "查询/创建"
    AuthMiddleware --> Config : "读取"
    AuthMiddleware --> Types : "使用"
    Security --> ErrorHandler : "配合"
    RateLimiter --> Config : "读取"
    

    图表来源

    • server/src/modules/auth/auth.controller.ts:1-94
    • server/src/modules/auth/auth.service.ts:1-115
    • server/src/middleware/auth.ts:1-81
    • server/src/middleware/errorHandler.ts:1-67
    • server/src/middleware/security.ts:1-154
    • server/src/middleware/rate-limiter.ts:1-120
    • server/src/config/index.ts:1-117
    • server/src/types/index.ts:1-124
    • server/src/models/index.ts:1-15

    章节来源

    • server/src/modules/auth/auth.controller.ts:1-94
    • server/src/modules/auth/auth.service.ts:1-115
    • server/src/middleware/auth.ts:1-81
    • server/src/middleware/errorHandler.ts:1-67
    • server/src/middleware/security.ts:1-154
    • server/src/middleware/rate-limiter.ts:1-120
    • server/src/config/index.ts:1-117
    • server/src/types/index.ts:1-124
    • server/src/models/index.ts:1-15

    性能考量

    • 限流策略:针对登录、验证码、TTS 生成、文件上传分别设置限流,避免滥用
    • 缓存与降级:Redis 可用时优先使用 Redis 限流器,不可用时回退内存限流器
    • 日志与监控:统一错误处理与性能监控中间件,结合 Sentry 进行错误追踪
    • 上传优化:建议使用对象存储(OSS)替代本地磁盘,提升并发与可靠性
    • 数据库:合理索引(手机号、OpenID 等)减少查询延迟

    章节来源

    • server/src/middleware/rate-limiter.ts:1-120
    • server/src/app.ts:64-69
    • server/src/app.ts:134-151

    故障排查指南

    • 未携带 Authorization 或格式错误
      • 现象:返回未授权错误
      • 处理:确认请求头格式为 Bearer Token
    • Token 已过期或无效
      • 现象:返回 Token 已过期或无效
      • 处理:引导用户重新登录获取新 Token
    • 验证码错误或过期
      • 现象:登录失败
      • 处理:重新发送验证码或检查验证码有效期
    • 用户不存在
      • 现象:更新用户信息时报错
      • 处理:确认用户已登录并存在
    • 参数错误
      • 现象:返回参数错误
      • 处理:检查手机号格式与必填字段

    章节来源

    • server/src/middleware/auth.ts:22-48
    • server/src/modules/auth/auth.controller.ts:36-43
    • server/src/modules/auth/auth.service.ts:22-32
    • server/src/middleware/errorHandler.ts:26-67

    结论

    本认证系统以手机号登录为核心,结合 JWT 实现轻量级身份认证,并通过中间件层提供安全与限流保障。当前未实现 Token 刷新与密码加密存储,建议在后续版本中引入 Refresh Token 与更强的密码安全策略;同时可迁移上传存储至对象存储并完善权限分级与配额控制,进一步提升安全性与可扩展性。

    附录

    数据模型(用户)

    erDiagram
    USER {
    int id PK
    string phone
    string openid
    string nickname
    string avatar
    int memberLevel
    datetime memberExpireAt
    int dailyUsage
    string lastUsageDate
    datetime createdAt
    datetime updatedAt
    }
    

    图表来源

    • server/prisma/schema.prisma:10-38

    类型定义(关键)

    • JwtPayload:包含 userId、phone、iat、exp
    • MemberLevel:0 免费、1 月度、2 年度
    • ApiResponse:统一响应结构(code/message/data)

    章节来源

    • server/src/types/index.ts:66-89
    • server/src/types/index.ts:18