Files
dashboard/.qoder/repowiki/zh/content/后端API文档/认证系统API.md
T
2026-06-30 14:46:52 +08:00

426 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 认证系统API
<cite>
**本文引用的文件**
- [backend/src/routes/auth.js](file://backend/src/routes/auth.js)
- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js)
- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js)
- [backend/src/utils/password.js](file://backend/src/utils/password.js)
- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js)
- [backend/src/utils/response.js](file://backend/src/utils/response.js)
- [backend/src/app.js](file://backend/src/app.js)
- [backend/src/config/env.js](file://backend/src/config/env.js)
- [backend/src/config/database.js](file://backend/src/config/database.js)
- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js)
- [backend/src/routes/index.js](file://backend/src/routes/index.js)
- [frontend/src/api/auth.js](file://frontend/src/api/auth.js)
- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js)
- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件为认证系统API的详细RESTful文档,覆盖用户登录、查询当前用户、修改密码等认证相关接口;说明JWT令牌生成、验证与过期处理机制;提供认证中间件使用示例与错误处理策略;记录密码加密方式、令牌有效期与安全最佳实践,并给出常见认证场景、客户端实现指南与调试技巧。
## 项目结构
后端采用Express + Sequelize架构,前端基于Vue 3 + Element Plus。认证相关逻辑集中在后端路由、中间件与工具模块,前端提供登录页面与认证状态管理。
```mermaid
graph TB
subgraph "后端"
A["应用入口<br/>app.js"]
B["路由汇总<br/>routes/index.js"]
C["认证路由<br/>routes/auth.js"]
D["认证中间件<br/>middleware/auth.js"]
E["JWT 工具<br/>utils/jwt.js"]
F["密码工具<br/>utils/password.js"]
G["响应封装<br/>utils/response.js"]
H["用户模型<br/>models/DashboardUser.js"]
I["环境配置<br/>config/env.js"]
J["数据库配置<br/>config/database.js"]
K["引导服务<br/>services/userBootstrap.js"]
end
subgraph "前端"
L["登录视图<br/>frontend/views/login/index.vue"]
M["认证API封装<br/>frontend/api/auth.js"]
N["认证状态工具<br/>frontend/utils/auth.js"]
end
A --> B
B --> C
C --> D
C --> E
C --> F
C --> G
C --> H
A --> I
A --> J
A --> K
L --> M
M --> N
```
**图表来源**
- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37)
- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12)
- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28)
- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58)
- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13)
- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24)
- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28)
- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151)
- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24)
- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99)
**章节来源**
- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37)
- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12)
## 核心组件
- 认证路由:提供登录、查询当前用户、修改密码接口。
- 认证中间件:校验Authorization头中的Bearer Token,解析并注入用户信息。
- JWT工具:签发访问令牌、解码验证、计算过期秒数。
- 密码工具:PBKDF2加盐哈希与安全比对。
- 用户模型:存储用户名、密码哈希、状态、最后登录时间等。
- 响应封装:统一返回格式(code/msg/data)。
- 引导服务:首次启动自动创建超级管理员账号。
**章节来源**
- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109)
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
- [backend/src/utils/jwt.js:7-25](file://backend/src/utils/jwt.js#L7-L25)
- [backend/src/utils/password.js:10-34](file://backend/src/utils/password.js#L10-L34)
- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54)
- [backend/src/utils/response.js:1-13](file://backend/src/utils/response.js#L1-L13)
- [backend/src/services/userBootstrap.js:5-24](file://backend/src/services/userBootstrap.js#L5-L24)
## 架构总览
认证流程概览:客户端发起登录请求,后端验证凭据并签发JWT;后续请求携带Authorization: Bearer <token>,中间件解码并校验,注入用户上下文;支持查询当前用户与修改密码。
```mermaid
sequenceDiagram
participant FE as "前端"
participant API as "认证路由(auth.js)"
participant MW as "认证中间件(auth.js)"
participant JWT as "JWT工具(jwt.js)"
participant PWD as "密码工具(password.js)"
participant DB as "用户模型(DashboardUser)"
FE->>API : "POST /api/auth/login"
API->>DB : "按用户名查询用户"
API->>PWD : "verifyPassword(明文, 存储哈希)"
PWD-->>API : "验证结果"
API->>JWT : "createAccessToken(用户)"
JWT-->>API : "access_token"
API-->>FE : "返回 {access_token, token_type, expires_in, user}"
FE->>API : "GET /api/auth/me"
API->>MW : "authMiddleware"
MW->>JWT : "decodeToken"
JWT-->>MW : "payload"
MW-->>API : "注入 req.user"
API->>DB : "findByPk(req.user.id)"
DB-->>API : "用户信息"
API-->>FE : "返回当前用户"
FE->>API : "PUT /api/auth/password"
API->>MW : "authMiddleware"
MW-->>API : "注入 req.user"
API->>PWD : "verifyPassword(旧密码)"
PWD-->>API : "验证结果"
API->>DB : "更新 password_hash"
API-->>FE : "返回修改结果"
```
**图表来源**
- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109)
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
- [backend/src/utils/jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21)
- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34)
- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54)
## 详细组件分析
### 接口定义与调用规范
- 登录接口
- 方法与路径:POST /api/auth/login
- 请求体字段:
- username: string(必填,前后去空格)
- password: string(必填)
- 成功响应数据:
- access_token: stringJWT
- token_type: string(固定为 bearer
- expires_in: number(秒,令牌有效期)
- user: objectid, username, is_super_admin, status, last_login_at, create_at, update_at
- 错误响应:
- 用户名或密码为空:返回错误
- 用户不存在或状态非启用:返回错误
- 密码错误:返回错误
- 其他异常:返回登录失败
- 查询当前用户接口
- 方法与路径:GET /api/auth/me
- 认证要求:必须携带 Authorization: Bearer <token>
- 成功响应数据:当前用户对象(同上)
- 错误响应:
- 未登录/缺少凭证:401
- 无效凭证/过期:401
- 账号不存在或已禁用:401
- 修改密码接口
- 方法与路径:PUT /api/auth/password
- 认证要求:必须携带 Authorization: Bearer <token>
- 请求体字段:
- old_password: string(必填)
- new_password: string(必填,至少6位)
- 成功响应:返回操作成功消息
- 错误响应:
- 参数缺失:返回错误
- 新密码长度不足:返回错误
- 旧密码错误:返回错误
- 账号不存在或已禁用:401
- 其他异常:返回修改失败
**章节来源**
- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109)
- [backend/src/utils/response.js:1-13](file://backend/src/utils/response.js#L1-L13)
### JWT令牌机制
- 生成:
- 使用HS256算法签名,密钥来自环境变量(默认开发值)。
- 载荷包含:sub(用户ID)、username、is_super_admin、iat(签发时间)、exp(过期时间,12小时)。
- 验证:
- 使用相同密钥与算法进行verify。
- 若抛出TokenExpiredError,返回“登录已过期,请重新登录”。
- 刷新:
- 当前实现不提供专用刷新接口;建议客户端在过期前重新登录以获取新令牌。
```mermaid
flowchart TD
Start(["开始"]) --> Gen["签发访问令牌<br/>createAccessToken"]
Gen --> Payload["载荷: sub, username, is_super_admin, iat, exp"]
Payload --> Sign["HS256签名"]
Sign --> Token["返回 access_token"]
Token --> Verify["解码验证<br/>decodeToken"]
Verify --> Expired{"是否过期?"}
Expired --> |是| ErrExp["返回 401: 登录已过期"]
Expired --> |否| OK["返回有效载荷"]
```
**图表来源**
- [backend/src/utils/jwt.js:7-25](file://backend/src/utils/jwt.js#L7-L25)
- [backend/src/middleware/auth.js:19-25](file://backend/src/middleware/auth.js#L19-L25)
**章节来源**
- [backend/src/utils/jwt.js:3-25](file://backend/src/utils/jwt.js#L3-L25)
- [backend/src/middleware/auth.js:19-25](file://backend/src/middleware/auth.js#L19-L25)
### 密码加密与校验
- 加密:
- PBKDF2,迭代次数、密钥长度、摘要算法均固定。
- 存储格式:前缀+摘要算法+迭代次数+盐+十六进制哈希。
- 校验:
- 安全比对,避免时序攻击。
- 不匹配或格式不合法直接返回false。
```mermaid
flowchart TD
A["输入明文密码"] --> B["解析存储格式"]
B --> C{"格式合法?"}
C --> |否| F["返回 false"]
C --> |是| D["提取 salt/迭代次数/摘要算法/期望哈希"]
D --> E["PBKDF2 计算哈希"]
E --> G["timingSafeEqual 安全比较"]
G --> H{"一致?"}
H --> |是| T["返回 true"]
H --> |否| F
```
**图表来源**
- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34)
**章节来源**
- [backend/src/utils/password.js:10-34](file://backend/src/utils/password.js#L10-L34)
- [backend/src/models/DashboardUser.js:17-21](file://backend/src/models/DashboardUser.js#L17-L21)
### 认证中间件与使用示例
- 校验规则:
- 必须存在Authorization头且以Bearer开头。
- 解码失败或载荷无sub则视为无效凭证。
- 过期异常返回“登录已过期,请重新登录”。
- 注入上下文:
- 成功后在req.user中注入:id、username、is_super_admin。
- 超级管理员校验:
- 提供requireSuperAdmin中间件,用于需要超级管理员权限的路由。
```mermaid
flowchart TD
S["进入中间件"] --> H1["读取 Authorization 头"]
H1 --> Check{"以 Bearer 开头?"}
Check --> |否| R401["返回 401: 未登录或缺少凭证"]
Check --> |是| Decode["decodeToken"]
Decode --> Valid{"载荷有效且含 sub?"}
Valid --> |否| R401B["返回 401: 无效凭证"]
Valid --> |是| Inject["注入 req.user"]
Inject --> Next["放行 next()"]
```
**图表来源**
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
**章节来源**
- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33)
### 数据模型与状态
- 用户表字段要点:
- 主键、唯一用户名、密码哈希、是否超级管理员、状态(启用/禁用)、最后登录时间、创建/更新时间。
- 登录成功后会更新last_login_at。
```mermaid
erDiagram
DASHBOARD_USER {
int id PK
string username UK
string password_hash
tinyint is_super_admin
tinyint status
datetime last_login_at
datetime create_at
datetime update_at
}
```
**图表来源**
- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54)
**章节来源**
- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54)
- [backend/src/routes/auth.js:48-49](file://backend/src/routes/auth.js#L48-L49)
### 客户端实现指南
- 登录流程:
- 前端调用登录API,接收access_token与用户信息。
- 将token存入localStorage并设置用户信息,跳转首页。
- 携带令牌:
- 后续请求在请求头添加Authorization: Bearer <token>。
- 令牌过期处理:
- 前端可解析token的exp判断过期,提示重新登录。
- 修改密码:
- 调用修改密码接口,成功后提示并刷新用户信息。
```mermaid
sequenceDiagram
participant VUE as "登录页(index.vue)"
participant API as "API封装(auth.js)"
participant UTIL as "认证工具(auth.js)"
VUE->>API : "login({username,password})"
API-->>VUE : "返回 {code,data}"
VUE->>UTIL : "setToken(access_token)"
VUE->>UTIL : "setUser(user)"
VUE-->>VUE : "跳转首页"
```
**图表来源**
- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150)
- [frontend/src/api/auth.js:3-12](file://frontend/src/api/auth.js#L3-L12)
- [frontend/src/utils/auth.js:8-14](file://frontend/src/utils/auth.js#L8-L14)
**章节来源**
- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151)
- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24)
- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99)
## 依赖关系分析
- 路由依赖中间件与工具模块,统一返回格式。
- 中间件依赖JWT工具进行解码。
- 登录流程依赖密码工具与用户模型。
- 应用入口加载路由、中间件与数据库初始化。
```mermaid
graph LR
Routes["routes/auth.js"] --> MW["middleware/auth.js"]
Routes --> JWT["utils/jwt.js"]
Routes --> PWD["utils/password.js"]
Routes --> RESP["utils/response.js"]
Routes --> MODEL["models/DashboardUser.js"]
APP["app.js"] --> ROUTESIDX["routes/index.js"]
ROUTESIDX --> Routes
APP --> ENV["config/env.js"]
APP --> DB["config/database.js"]
APP --> BOOT["services/userBootstrap.js"]
```
**图表来源**
- [backend/src/routes/auth.js:1-11](file://backend/src/routes/auth.js#L1-L11)
- [backend/src/middleware/auth.js:1-1](file://backend/src/middleware/auth.js#L1-L1)
- [backend/src/utils/jwt.js:1-1](file://backend/src/utils/jwt.js#L1-L1)
- [backend/src/utils/password.js:1-2](file://backend/src/utils/password.js#L1-L2)
- [backend/src/utils/response.js:1-2](file://backend/src/utils/response.js#L1-L2)
- [backend/src/models/DashboardUser.js:1-2](file://backend/src/models/DashboardUser.js#L1-L2)
- [backend/src/app.js:10-12](file://backend/src/app.js#L10-L12)
- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12)
- [backend/src/config/env.js:1-2](file://backend/src/config/env.js#L1-L2)
- [backend/src/config/database.js:1-2](file://backend/src/config/database.js#L1-L2)
- [backend/src/services/userBootstrap.js:1-3](file://backend/src/services/userBootstrap.js#L1-L3)
**章节来源**
- [backend/src/app.js:10-12](file://backend/src/app.js#L10-L12)
- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12)
## 性能考虑
- 密码哈希迭代次数较高,确保安全性但会增加CPU开销;可在生产环境根据硬件能力评估。
- JWT签发/验证为轻量操作,主要成本在数据库查询与密码校验。
- 建议:
- 在高并发场景下,关注数据库连接池与索引(用户名唯一索引)。
- 对登录失败进行日志记录但避免泄露敏感信息。
## 故障排查指南
- 常见错误与定位:
- 401 未登录或缺少凭证:检查请求头Authorization是否正确。
- 401 无效凭证:检查JWT密钥、算法与签名一致性。
- 401 登录已过期:客户端需重新登录获取新令牌。
- 用户名或密码错误:确认用户名大小写、空格与密码哈希。
- 获取用户信息失败/修改密码失败:查看后端日志与数据库状态。
- 前端调试:
- 检查localStorage中的token是否存在与格式正确。
- 使用工具函数解析token的exp判断是否过期。
- 登录页提示“登录状态有效期12小时”,过期后需重新登录。
**章节来源**
- [backend/src/middleware/auth.js:5-25](file://backend/src/middleware/auth.js#L5-L25)
- [backend/src/routes/auth.js:37-46](file://backend/src/routes/auth.js#L37-L46)
- [frontend/src/views/login/index.vue:93-93](file://frontend/src/views/login/index.vue#L93-L93)
- [frontend/src/utils/auth.js:78-92](file://frontend/src/utils/auth.js#L78-L92)
## 结论
该认证系统采用JWT作为会话载体,结合强密码哈希与严格的中间件校验,提供了基础而完整的认证能力。建议在生产环境中:
- 设置稳定的JWT_SECRET
- 控制密码迭代次数与数据库性能;
- 在客户端实现令牌过期检测与自动重新登录;
- 对登录与修改密码接口增加限流与风控策略。
## 附录
### 环境变量与配置
- JWT_SECRET:JWT签名密钥(生产环境务必自定义)。
- DATABASE_*:数据库连接参数(名称、用户、密码、主机、端口)。
- DASHBOARD_ADMIN_USERNAME / DASHBOARD_ADMIN_PASSWORD:首次引导创建超级管理员的默认值。
- APP_ENV:环境标识(development/production)。
**章节来源**
- [backend/src/utils/jwt.js:3-3](file://backend/src/utils/jwt.js#L3-L3)
- [backend/src/config/database.js:4-21](file://backend/src/config/database.js#L4-L21)
- [backend/src/services/userBootstrap.js:9-10](file://backend/src/services/userBootstrap.js#L9-L10)
- [backend/src/config/env.js:7-10](file://backend/src/config/env.js#L7-L10)