413 lines
16 KiB
Markdown
413 lines
16 KiB
Markdown
# 认证接口
|
||
|
||
<cite>
|
||
**本文档引用的文件**
|
||
- [backend/app/api/auth.py](file://backend/app/api/auth.py)
|
||
- [backend/app/schemas/auth.py](file://backend/app/schemas/auth.py)
|
||
- [backend/app/services/auth.py](file://backend/app/services/auth.py)
|
||
- [backend/app/models/user.py](file://backend/app/models/user.py)
|
||
- [backend/app/api/deps.py](file://backend/app/api/deps.py)
|
||
- [backend/app/config.py](file://backend/app/config.py)
|
||
- [backend/app/main.py](file://backend/app/main.py)
|
||
- [backend/app/database.py](file://backend/app/database.py)
|
||
- [tests/test_auth.py](file://tests/test_auth.py)
|
||
- [backend/requirements.txt](file://backend/requirements.txt)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖分析](#依赖分析)
|
||
7. [性能考虑](#性能考虑)
|
||
8. [故障排除指南](#故障排除指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本文件为认证系统的完整API文档,覆盖以下接口:
|
||
- 用户注册:/api/v1/auth/register
|
||
- 用户登录:/api/v1/auth/login
|
||
- 获取当前用户:/api/v1/auth/me
|
||
|
||
文档详细说明每个接口的请求参数、响应格式、状态码、错误处理以及JWT令牌生成机制、认证流程与安全考虑,并提供认证中间件使用指南与最佳实践。
|
||
|
||
## 项目结构
|
||
后端采用FastAPI + SQLAlchemy异步ORM + PostgreSQL + Redis的架构,认证模块位于backend/app/api/auth.py,配合服务层、模型层与依赖注入实现。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "后端应用"
|
||
A["FastAPI 应用<br/>路由注册"]
|
||
B["认证路由<br/>/api/v1/auth/*"]
|
||
C["认证服务<br/>密码哈希/校验/JWT"]
|
||
D["数据库会话<br/>AsyncSession"]
|
||
E["用户模型<br/>SQLAlchemy ORM"]
|
||
F["认证依赖<br/>OAuth2PasswordBearer"]
|
||
end
|
||
A --> B
|
||
B --> C
|
||
B --> D
|
||
C --> D
|
||
D --> E
|
||
F --> C
|
||
F --> D
|
||
```
|
||
|
||
图表来源
|
||
- [backend/app/main.py:38](file://backend/app/main.py#L38)
|
||
- [backend/app/api/auth.py:10](file://backend/app/api/auth.py#L10)
|
||
- [backend/app/services/auth.py:13](file://backend/app/services/auth.py#L13)
|
||
- [backend/app/database.py:23](file://backend/app/database.py#L23)
|
||
- [backend/app/models/user.py:11](file://backend/app/models/user.py#L11)
|
||
- [backend/app/api/deps.py:13](file://backend/app/api/deps.py#L13)
|
||
|
||
章节来源
|
||
- [backend/app/main.py:38](file://backend/app/main.py#L38)
|
||
- [backend/app/api/auth.py:10](file://backend/app/api/auth.py#L10)
|
||
|
||
## 核心组件
|
||
- 路由器:在主应用中注册认证路由前缀为/api/v1/auth
|
||
- 认证服务:提供密码哈希/校验、JWT生成/校验、用户注册与认证
|
||
- 数据模型:用户表结构,包含邮箱、密码哈希、计划等级、配额等字段
|
||
- 依赖注入:OAuth2PasswordBearer用于从Authorization头提取Bearer令牌,get_current_user解析并验证JWT,加载当前用户
|
||
- 配置:JWT密钥与过期时间、数据库连接等
|
||
|
||
章节来源
|
||
- [backend/app/api/auth.py:10](file://backend/app/api/auth.py#L10)
|
||
- [backend/app/services/auth.py:13](file://backend/app/services/auth.py#L13)
|
||
- [backend/app/models/user.py:11](file://backend/app/models/user.py#L11)
|
||
- [backend/app/api/deps.py:13](file://backend/app/api/deps.py#L13)
|
||
- [backend/app/config.py:9](file://backend/app/config.py#L9)
|
||
|
||
## 架构总览
|
||
认证系统遵循“请求-服务-模型-数据库”的分层设计,使用OAuth2 Bearer令牌进行无状态认证。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant 客户端 as "客户端"
|
||
participant 路由 as "认证路由"
|
||
participant 服务 as "认证服务"
|
||
participant 数据库 as "数据库"
|
||
participant 依赖 as "认证依赖"
|
||
客户端->>路由 : POST /api/v1/auth/register
|
||
路由->>服务 : 注册用户(邮箱/密码/姓名)
|
||
服务->>数据库 : 查询邮箱是否已存在
|
||
数据库-->>服务 : 结果
|
||
服务->>服务 : 哈希密码
|
||
服务->>数据库 : 创建用户记录
|
||
数据库-->>服务 : 新用户对象
|
||
服务-->>路由 : 返回UserResponse
|
||
路由-->>客户端 : 201 Created + UserResponse
|
||
客户端->>路由 : POST /api/v1/auth/login
|
||
路由->>服务 : 认证(邮箱/密码)
|
||
服务->>数据库 : 查询用户
|
||
数据库-->>服务 : 用户或None
|
||
服务->>服务 : 校验密码
|
||
服务->>服务 : 生成JWT(access_token)
|
||
服务-->>路由 : 返回TokenResponse
|
||
路由-->>客户端 : 200 OK + TokenResponse
|
||
客户端->>依赖 : GET /api/v1/auth/me (Authorization : Bearer)
|
||
依赖->>依赖 : 解析并验证JWT
|
||
依赖->>数据库 : 按ID查询用户
|
||
数据库-->>依赖 : 用户对象
|
||
依赖-->>客户端 : 200 OK + UserResponse
|
||
```
|
||
|
||
图表来源
|
||
- [backend/app/api/auth.py:13](file://backend/app/api/auth.py#L13)
|
||
- [backend/app/api/auth.py:22](file://backend/app/api/auth.py#L22)
|
||
- [backend/app/api/auth.py:40](file://backend/app/api/auth.py#L40)
|
||
- [backend/app/services/auth.py:37](file://backend/app/services/auth.py#L37)
|
||
- [backend/app/services/auth.py:55](file://backend/app/services/auth.py#L55)
|
||
- [backend/app/api/deps.py:16](file://backend/app/api/deps.py#L16)
|
||
|
||
## 详细组件分析
|
||
|
||
### 用户注册接口 /api/v1/auth/register
|
||
- 方法与路径:POST /api/v1/auth/register
|
||
- 请求体模型:UserRegister
|
||
- 字段:email(邮箱)、password(字符串,最小长度8)、name(字符串,1-100)
|
||
- 响应模型:UserResponse
|
||
- 字段:id(UUID)、email(字符串)、name(可空)、plan(字符串,默认"free")、max_queries(整数,默认5)、is_active(布尔,默认true)、created_at(时间戳)
|
||
- 成功响应:201 Created
|
||
- 错误响应:
|
||
- 400 Bad Request:当邮箱已被注册时,返回错误详情
|
||
- 处理流程:
|
||
- 调用注册服务,检查邮箱唯一性
|
||
- 对密码进行哈希处理
|
||
- 写入数据库并返回新用户信息
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["请求进入"]) --> Validate["校验请求体<br/>邮箱/密码/姓名"]
|
||
Validate --> CheckDup{"邮箱已存在?"}
|
||
CheckDup --> |是| Return400["返回400错误<br/>邮箱已注册"]
|
||
CheckDup --> |否| HashPwd["哈希密码"]
|
||
HashPwd --> Create["创建用户记录"]
|
||
Create --> Commit["提交事务"]
|
||
Commit --> Refresh["刷新用户对象"]
|
||
Refresh --> Return201["返回201 + UserResponse"]
|
||
```
|
||
|
||
图表来源
|
||
- [backend/app/api/auth.py:13](file://backend/app/api/auth.py#L13)
|
||
- [backend/app/services/auth.py:37](file://backend/app/services/auth.py#L37)
|
||
- [backend/app/schemas/auth.py:7](file://backend/app/schemas/auth.py#L7)
|
||
- [backend/app/schemas/auth.py:18](file://backend/app/schemas/auth.py#L18)
|
||
|
||
章节来源
|
||
- [backend/app/api/auth.py:13](file://backend/app/api/auth.py#L13)
|
||
- [backend/app/schemas/auth.py:7](file://backend/app/schemas/auth.py#L7)
|
||
- [backend/app/schemas/auth.py:18](file://backend/app/schemas/auth.py#L18)
|
||
- [backend/app/services/auth.py:37](file://backend/app/services/auth.py#L37)
|
||
- [tests/test_auth.py:26](file://tests/test_auth.py#L26)
|
||
- [tests/test_auth.py:43](file://tests/test_auth.py#L43)
|
||
|
||
请求示例
|
||
- POST /api/v1/auth/register
|
||
- 请求体JSON:
|
||
- email: "string"
|
||
- password: "string(≥8)"
|
||
- name: "string(1-100)"
|
||
|
||
响应示例
|
||
- 201 Created
|
||
- 响应体JSON:
|
||
- id: "uuid"
|
||
- email: "string"
|
||
- name: "string|null"
|
||
- plan: "string"
|
||
- max_queries: integer
|
||
- is_active: boolean
|
||
- created_at: "datetime"
|
||
|
||
状态码
|
||
- 201 Created:注册成功
|
||
- 400 Bad Request:邮箱已注册
|
||
|
||
错误处理
|
||
- 当服务层抛出ValueError(如邮箱重复),路由捕获并返回400
|
||
|
||
### 用户登录接口 /api/v1/auth/login
|
||
- 方法与路径:POST /api/v1/auth/login
|
||
- 请求体模型:UserLogin
|
||
- 字段:email(邮箱)、password(字符串)
|
||
- 响应模型:TokenResponse
|
||
- 字段:access_token(字符串)、token_type(字符串,固定为"bearer")、user(UserResponse)
|
||
- 成功响应:200 OK
|
||
- 错误响应:
|
||
- 401 Unauthorized:邮箱或密码不正确,携带WWW-Authenticate: Bearer头
|
||
- 处理流程:
|
||
- 使用邮箱查询用户
|
||
- 校验密码哈希
|
||
- 生成JWT令牌(含过期时间),返回access_token与用户信息
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant 客户端 as "客户端"
|
||
participant 路由 as "登录路由"
|
||
participant 服务 as "认证服务"
|
||
participant 数据库 as "数据库"
|
||
客户端->>路由 : POST /api/v1/auth/login
|
||
路由->>服务 : authenticate_user(邮箱, 密码)
|
||
服务->>数据库 : 查询用户
|
||
数据库-->>服务 : 用户或None
|
||
服务->>服务 : 校验密码
|
||
alt 用户不存在或密码错误
|
||
服务-->>路由 : None
|
||
路由-->>客户端 : 401 Unauthorized
|
||
else 登录成功
|
||
服务-->>路由 : User对象
|
||
路由->>服务 : create_access_token({sub : userId})
|
||
服务-->>路由 : access_token
|
||
路由-->>客户端 : 200 OK + TokenResponse
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [backend/app/api/auth.py:22](file://backend/app/api/auth.py#L22)
|
||
- [backend/app/api/auth.py:24](file://backend/app/api/auth.py#L24)
|
||
- [backend/app/services/auth.py:55](file://backend/app/services/auth.py#L55)
|
||
- [backend/app/services/auth.py:24](file://backend/app/services/auth.py#L24)
|
||
|
||
章节来源
|
||
- [backend/app/api/auth.py:22](file://backend/app/api/auth.py#L22)
|
||
- [backend/app/api/auth.py:24](file://backend/app/api/auth.py#L24)
|
||
- [backend/app/schemas/auth.py:13](file://backend/app/schemas/auth.py#L13)
|
||
- [backend/app/schemas/auth.py:30](file://backend/app/schemas/auth.py#L30)
|
||
- [backend/app/services/auth.py:55](file://backend/app/services/auth.py#L55)
|
||
- [backend/app/services/auth.py:24](file://backend/app/services/auth.py#L24)
|
||
- [tests/test_auth.py:62](file://tests/test_auth.py#L62)
|
||
- [tests/test_auth.py:76-84](file://tests/test_auth.py#L76-L84)
|
||
|
||
请求示例
|
||
- POST /api/v1/auth/login
|
||
- 请求体JSON:
|
||
- email: "string"
|
||
- password: "string"
|
||
|
||
响应示例
|
||
- 200 OK
|
||
- 响应体JSON:
|
||
- access_token: "string"
|
||
- token_type: "bearer"
|
||
- user: {
|
||
id: "uuid"
|
||
email: "string"
|
||
name: "string|null"
|
||
plan: "string"
|
||
max_queries: integer
|
||
is_active: boolean
|
||
created_at: "datetime"
|
||
}
|
||
|
||
状态码
|
||
- 200 OK:登录成功
|
||
- 401 Unauthorized:邮箱或密码不正确
|
||
|
||
安全考虑
|
||
- 密码使用BCrypt哈希存储
|
||
- JWT使用HS256算法与密钥签名,过期时间由配置控制
|
||
- 登录失败返回统一错误消息,避免泄露账户存在性细节
|
||
|
||
### 获取当前用户接口 /api/v1/auth/me
|
||
- 方法与路径:GET /api/v1/auth/me
|
||
- 权限要求:需要Bearer令牌(Authorization: Bearer <token>)
|
||
- 依赖注入:get_current_user
|
||
- 通过OAuth2PasswordBearer从Authorization头提取令牌
|
||
- 校验JWT并解析sub(用户ID)
|
||
- 从数据库按ID查询用户并返回
|
||
- 响应模型:UserResponse
|
||
- 成功响应:200 OK
|
||
- 错误响应:
|
||
- 401 Unauthorized:令牌无效、过期或用户不存在
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant 客户端 as "客户端"
|
||
participant 依赖 as "get_current_user"
|
||
participant 服务 as "verify_token"
|
||
participant 数据库 as "数据库"
|
||
客户端->>依赖 : GET /api/v1/auth/me (Authorization : Bearer)
|
||
依赖->>依赖 : 从Authorization头提取token
|
||
依赖->>服务 : verify_token(token)
|
||
服务-->>依赖 : payload(sub=userId)
|
||
依赖->>数据库 : 查询用户by id
|
||
数据库-->>依赖 : 用户或None
|
||
alt 令牌无效/用户不存在
|
||
依赖-->>客户端 : 401 Unauthorized
|
||
else 成功
|
||
依赖-->>客户端 : 200 OK + UserResponse
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [backend/app/api/deps.py:16](file://backend/app/api/deps.py#L16)
|
||
- [backend/app/api/deps.py:27](file://backend/app/api/deps.py#L27)
|
||
- [backend/app/services/auth.py:32](file://backend/app/services/auth.py#L32)
|
||
- [backend/app/api/auth.py:40](file://backend/app/api/auth.py#L40)
|
||
|
||
章节来源
|
||
- [backend/app/api/auth.py:40](file://backend/app/api/auth.py#L40)
|
||
- [backend/app/api/deps.py:16](file://backend/app/api/deps.py#L16)
|
||
- [backend/app/api/deps.py:27](file://backend/app/api/deps.py#L27)
|
||
- [backend/app/services/auth.py:32](file://backend/app/services/auth.py#L32)
|
||
- [tests/test_auth.py:88](file://tests/test_auth.py#L88)
|
||
- [tests/test_auth.py:99](file://tests/test_auth.py#L99)
|
||
|
||
请求示例
|
||
- GET /api/v1/auth/me
|
||
- 请求头:
|
||
- Authorization: "Bearer <access_token>"
|
||
|
||
响应示例
|
||
- 200 OK
|
||
- 响应体JSON:UserResponse
|
||
|
||
状态码
|
||
- 200 OK:成功获取当前用户
|
||
- 401 Unauthorized:未提供有效令牌或令牌无效
|
||
|
||
## 依赖分析
|
||
- 外部库依赖:FastAPI、SQLAlchemy异步、Pydantic、python-jose、passlib、redis、apscheduler、playwright等
|
||
- 认证相关依赖:OAuth2PasswordBearer、JWT编码/解码、BCrypt密码哈希
|
||
- 配置项:JWT_SECRET、JWT_EXPIRE_HOURS、DATABASE_URL、REDIS_URL
|
||
|
||
```mermaid
|
||
graph LR
|
||
A["FastAPI 应用"] --> B["认证路由"]
|
||
B --> C["认证服务"]
|
||
C --> D["Passlib(Bcrypt)"]
|
||
C --> E["python-jose(JWT)"]
|
||
C --> F["SQLAlchemy 异步"]
|
||
F --> G["PostgreSQL"]
|
||
A --> H["CORS 中间件"]
|
||
A --> I["依赖注入容器"]
|
||
```
|
||
|
||
图表来源
|
||
- [backend/requirements.txt:2](file://backend/requirements.txt#L2)
|
||
- [backend/requirements.txt:16](file://backend/requirements.txt#L16)
|
||
- [backend/requirements.txt:17](file://backend/requirements.txt#L17)
|
||
- [backend/app/main.py:30](file://backend/app/main.py#L30)
|
||
- [backend/app/api/deps.py:13](file://backend/app/api/deps.py#L13)
|
||
- [backend/app/services/auth.py:13](file://backend/app/services/auth.py#L13)
|
||
|
||
章节来源
|
||
- [backend/requirements.txt:2](file://backend/requirements.txt#L2)
|
||
- [backend/requirements.txt:16](file://backend/requirements.txt#L16)
|
||
- [backend/requirements.txt:17](file://backend/requirements.txt#L17)
|
||
- [backend/app/main.py:30](file://backend/app/main.py#L30)
|
||
- [backend/app/api/deps.py:13](file://backend/app/api/deps.py#L13)
|
||
- [backend/app/services/auth.py:13](file://backend/app/services/auth.py#L13)
|
||
|
||
## 性能考虑
|
||
- 数据库访问:注册与登录均执行单次查询,使用异步会话减少阻塞
|
||
- 密码哈希:BCrypt成本因子默认设置,平衡安全性与性能
|
||
- JWT过期:可通过配置调整过期时间,建议根据业务场景权衡
|
||
- 缓存策略:当前未对用户信息做缓存,可在高频读取场景引入Redis缓存
|
||
|
||
## 故障排除指南
|
||
- 注册失败(400):确认邮箱唯一性;检查请求体字段类型与长度
|
||
- 登录失败(401):确认邮箱与密码正确;检查JWT密钥与过期时间配置
|
||
- 获取当前用户失败(401):确认Authorization头格式为Bearer <token>;检查令牌是否过期
|
||
- 数据库连接问题:检查DATABASE_URL配置;确保PostgreSQL服务可用
|
||
- CORS跨域问题:确认前端域名已在CORS允许列表中
|
||
|
||
章节来源
|
||
- [tests/test_auth.py:43](file://tests/test_auth.py#L43)
|
||
- [tests/test_auth.py:76-84](file://tests/test_auth.py#L76-L84)
|
||
- [tests/test_auth.py:99](file://tests/test_auth.py#L99)
|
||
- [backend/app/config.py:7](file://backend/app/config.py#L7)
|
||
- [backend/app/main.py:30](file://backend/app/main.py#L30)
|
||
|
||
## 结论
|
||
认证系统基于FastAPI与SQLAlchemy异步ORM构建,采用OAuth2 Bearer令牌与JWT实现无状态认证。注册与登录流程清晰,错误处理明确,具备良好的扩展性与安全性基础。建议在生产环境完善令牌刷新策略、速率限制与审计日志,并定期轮换JWT密钥。
|
||
|
||
## 附录
|
||
|
||
### JWT令牌生成机制
|
||
- 签名算法:HS256
|
||
- 过期时间:由配置JWT_EXPIRE_HOURS决定
|
||
- 载荷:包含sub(用户ID)与exp(过期时间)
|
||
- 生成流程:在登录成功后调用create_access_token(data={"sub": str(user.id)})
|
||
|
||
章节来源
|
||
- [backend/app/services/auth.py:24](file://backend/app/services/auth.py#L24)
|
||
- [backend/app/services/auth.py:26](file://backend/app/services/auth.py#L26)
|
||
- [backend/app/config.py:10](file://backend/app/config.py#L10)
|
||
|
||
### 认证中间件使用指南与最佳实践
|
||
- 在需要保护的路由上使用依赖注入:Depends(get_current_user)
|
||
- 前端在每次请求中携带Authorization: Bearer <access_token>
|
||
- 生产环境务必设置安全的JWT_SECRET并启用HTTPS
|
||
- 建议实现令牌刷新与登出机制,避免长期持有高权限令牌
|
||
- 对登录失败与敏感操作增加速率限制与日志审计
|
||
|
||
章节来源
|
||
- [backend/app/api/deps.py:16](file://backend/app/api/deps.py#L16)
|
||
- [backend/app/api/auth.py:40](file://backend/app/api/auth.py#L40)
|
||
- [backend/app/config.py:9](file://backend/app/config.py#L9) |