# 用户认证系统

<cite>
**本文引用的文件**
- [server/src/modules/auth/auth.controller.ts](file://server/src/modules/auth/auth.controller.ts)
- [server/src/modules/auth/auth.service.ts](file://server/src/modules/auth/auth.service.ts)
- [server/src/middleware/auth.ts](file://server/src/middleware/auth.ts)
- [server/src/config/index.ts](file://server/src/config/index.ts)
- [server/src/types/index.ts](file://server/src/types/index.ts)
- [server/src/models/index.ts](file://server/src/models/index.ts)
- [server/prisma/schema.prisma](file://server/prisma/schema.prisma)
- [server/src/middleware/errorHandler.ts](file://server/src/middleware/errorHandler.ts)
- [server/src/middleware/security.ts](file://server/src/middleware/security.ts)
- [server/src/middleware/rate-limiter.ts](file://server/src/middleware/rate-limiter.ts)
- [server/src/app.ts](file://server/src/app.ts)
- [deploy-package/server/modules/auth/auth.controller.js](file://deploy-package/server/modules/auth/auth.controller.js)
- [deploy-package/server/modules/auth/auth.service.js](file://deploy-package/server/modules/auth/auth.service.js)
</cite>

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

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

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

```mermaid
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](file://server/src/app.ts#L1-L194)
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/middleware/security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/middleware/auth.ts:1-81](file://server/src/middleware/auth.ts#L1-L81)
- [server/src/modules/auth/auth.controller.ts:1-94](file://server/src/modules/auth/auth.controller.ts#L1-L94)
- [server/src/modules/auth/auth.service.ts:1-115](file://server/src/modules/auth/auth.service.ts#L1-L115)
- [server/src/config/index.ts:1-117](file://server/src/config/index.ts#L1-L117)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/src/models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)
- [server/prisma/schema.prisma:1-472](file://server/prisma/schema.prisma#L1-L472)

章节来源
- [server/src/app.ts:1-194](file://server/src/app.ts#L1-L194)
- [server/src/modules/auth/auth.controller.ts:1-94](file://server/src/modules/auth/auth.controller.ts#L1-L94)
- [server/src/modules/auth/auth.service.ts:1-115](file://server/src/modules/auth/auth.service.ts#L1-L115)

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

章节来源
- [server/src/modules/auth/auth.controller.ts:1-94](file://server/src/modules/auth/auth.controller.ts#L1-L94)
- [server/src/modules/auth/auth.service.ts:1-115](file://server/src/modules/auth/auth.service.ts#L1-L115)
- [server/src/middleware/auth.ts:1-81](file://server/src/middleware/auth.ts#L1-L81)
- [server/src/middleware/security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/config/index.ts:1-117](file://server/src/config/index.ts#L1-L117)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/src/models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)
- [server/prisma/schema.prisma:1-472](file://server/prisma/schema.prisma#L1-L472)

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

```mermaid
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](file://server/src/app.ts#L1-L194)
- [server/src/modules/auth/auth.controller.ts:1-94](file://server/src/modules/auth/auth.controller.ts#L1-L94)
- [server/src/modules/auth/auth.service.ts:1-115](file://server/src/modules/auth/auth.service.ts#L1-L115)
- [server/src/models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)
- [server/prisma/schema.prisma:1-472](file://server/prisma/schema.prisma#L1-L472)

## 详细组件分析

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

```mermaid
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](file://server/src/modules/auth/auth.controller.ts#L32-L52)
- [server/src/modules/auth/auth.service.ts:44-97](file://server/src/modules/auth/auth.service.ts#L44-L97)

章节来源
- [server/src/modules/auth/auth.controller.ts:32-52](file://server/src/modules/auth/auth.controller.ts#L32-L52)
- [server/src/modules/auth/auth.service.ts:44-97](file://server/src/modules/auth/auth.service.ts#L44-L97)

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

```mermaid
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](file://server/src/modules/auth/auth.service.ts#L34-L41)
- [server/src/middleware/auth.ts:7-49](file://server/src/middleware/auth.ts#L7-L49)
- [server/src/config/index.ts:77-81](file://server/src/config/index.ts#L77-L81)

章节来源
- [server/src/modules/auth/auth.service.ts:34-41](file://server/src/modules/auth/auth.service.ts#L34-L41)
- [server/src/middleware/auth.ts:7-49](file://server/src/middleware/auth.ts#L7-L49)
- [server/src/config/index.ts:77-81](file://server/src/config/index.ts#L77-L81)

### 认证中间件实现原理
- 支持强制认证与可选认证两种模式
- 强制认证：必须携带合法 Bearer Token，否则抛出未授权错误
- 可选认证：若携带非法 Token，则回退为测试用户上下文
- 开发模式：可通过环境变量开关跳过认证

```mermaid
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](file://server/src/middleware/auth.ts#L51-L81)
- [server/src/middleware/auth.ts:7-49](file://server/src/middleware/auth.ts#L7-L49)

章节来源
- [server/src/middleware/auth.ts:51-81](file://server/src/middleware/auth.ts#L51-L81)
- [server/src/middleware/auth.ts:7-49](file://server/src/middleware/auth.ts#L7-L49)

### 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](file://server/src/modules/auth/auth.service.ts#L34-L41)
- [server/src/config/index.ts:77-81](file://server/src/config/index.ts#L77-L81)

### 用户注册流程
- 若手机号对应的用户不存在，则创建默认用户（昵称、头像、会员等级、用量统计等字段初始化）
- 新用户标记为“isNewUser”返回给前端

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

图表来源
- [server/src/modules/auth/auth.service.ts:66-82](file://server/src/modules/auth/auth.service.ts#L66-L82)

章节来源
- [server/src/modules/auth/auth.service.ts:66-82](file://server/src/modules/auth/auth.service.ts#L66-L82)

### 登录验证逻辑
- 手机号格式校验
- 验证码校验（开发环境可跳过）
- 用户查找/创建
- JWT 签发
- 统一响应包装

章节来源
- [server/src/modules/auth/auth.controller.ts:32-52](file://server/src/modules/auth/auth.controller.ts#L32-L52)
- [server/src/modules/auth/auth.service.ts:44-97](file://server/src/modules/auth/auth.service.ts#L44-L97)

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

章节来源
- [server/src/modules/auth/auth.service.ts:11-32](file://server/src/modules/auth/auth.service.ts#L11-L32)

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

章节来源
- [server/src/config/index.ts:113-117](file://server/src/config/index.ts#L113-L117)
- [server/src/app.ts:76-83](file://server/src/app.ts#L76-L83)

### 用户权限控制策略
- 会员等级：0（免费）、1（月度）、2（年度）
- 会员配额：每日生成次数、单次字数上限
- 免费用户：较低配额
- 月度/年度用户：更高配额或无限制
- 限流策略：按用户等级差异化限流

章节来源
- [server/src/types/index.ts:18-124](file://server/src/types/index.ts#L18-L124)
- [server/src/middleware/rate-limiter.ts:106-110](file://server/src/middleware/rate-limiter.ts#L106-L110)

### 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 <token>
  - 响应：
    - code: number（0 表示成功）
    - message: string
    - data: { id, phone, nickname, avatar, memberLevel, memberExpireAt, dailyUsage }
  - 错误码：401（未授权）、404（用户不存在）

- 更新用户信息
  - 方法与路径：PUT /api/auth/user-info
  - 请求头：Authorization: Bearer <token>
  - 请求参数：nickname: string（可选）、avatar: string（可选）
  - 响应：
    - code: number（0 表示成功）
    - message: string
    - data: { nickname, avatar }
  - 错误码：400（用户不存在）、401（未授权）

章节来源
- [server/src/modules/auth/auth.controller.ts:10-92](file://server/src/modules/auth/auth.controller.ts#L10-L92)
- [server/src/modules/auth/auth.service.ts:99-115](file://server/src/modules/auth/auth.service.ts#L99-L115)

## 依赖关系分析

```mermaid
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](file://server/src/modules/auth/auth.controller.ts#L1-L94)
- [server/src/modules/auth/auth.service.ts:1-115](file://server/src/modules/auth/auth.service.ts#L1-L115)
- [server/src/middleware/auth.ts:1-81](file://server/src/middleware/auth.ts#L1-L81)
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/middleware/security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/config/index.ts:1-117](file://server/src/config/index.ts#L1-L117)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/src/models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)

章节来源
- [server/src/modules/auth/auth.controller.ts:1-94](file://server/src/modules/auth/auth.controller.ts#L1-L94)
- [server/src/modules/auth/auth.service.ts:1-115](file://server/src/modules/auth/auth.service.ts#L1-L115)
- [server/src/middleware/auth.ts:1-81](file://server/src/middleware/auth.ts#L1-L81)
- [server/src/middleware/errorHandler.ts:1-67](file://server/src/middleware/errorHandler.ts#L1-L67)
- [server/src/middleware/security.ts:1-154](file://server/src/middleware/security.ts#L1-L154)
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/config/index.ts:1-117](file://server/src/config/index.ts#L1-L117)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/src/models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)

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

章节来源
- [server/src/middleware/rate-limiter.ts:1-120](file://server/src/middleware/rate-limiter.ts#L1-L120)
- [server/src/app.ts:64-69](file://server/src/app.ts#L64-L69)
- [server/src/app.ts:134-151](file://server/src/app.ts#L134-L151)

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

章节来源
- [server/src/middleware/auth.ts:22-48](file://server/src/middleware/auth.ts#L22-L48)
- [server/src/modules/auth/auth.controller.ts:36-43](file://server/src/modules/auth/auth.controller.ts#L36-L43)
- [server/src/modules/auth/auth.service.ts:22-32](file://server/src/modules/auth/auth.service.ts#L22-L32)
- [server/src/middleware/errorHandler.ts:26-67](file://server/src/middleware/errorHandler.ts#L26-L67)

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

## 附录

### 数据模型（用户）
```mermaid
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](file://server/prisma/schema.prisma#L10-L38)

### 类型定义（关键）
- JwtPayload：包含 userId、phone、iat、exp
- MemberLevel：0 免费、1 月度、2 年度
- ApiResponse：统一响应结构（code/message/data）

章节来源
- [server/src/types/index.ts:66-89](file://server/src/types/index.ts#L66-L89)
- [server/src/types/index.ts:18](file://server/src/types/index.ts#L18)