chore(git): 更新.gitignore以忽略新的本地文件
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
This commit is contained in:
330
.qoder/repowiki/zh/content/API参考/认证API/发送验证码.md
Normal file
330
.qoder/repowiki/zh/content/API参考/认证API/发送验证码.md
Normal file
@@ -0,0 +1,330 @@
|
||||
# 发送验证码
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go)
|
||||
- [routes.go](file://internal/handler/routes.go)
|
||||
- [verification_service.go](file://internal/service/verification_service.go)
|
||||
- [common.go](file://internal/types/common.go)
|
||||
- [email.go](file://pkg/email/email.go)
|
||||
- [manager.go](file://pkg/email/manager.go)
|
||||
- [redis.go](file://pkg/redis/redis.go)
|
||||
- [manager.go](file://pkg/redis/manager.go)
|
||||
- [config.go](file://pkg/config/config.go)
|
||||
- [main.go](file://cmd/server/main.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向“发送验证码”API,围绕 /api/v1/auth/send-code 端点进行完整说明。内容包括:
|
||||
- 接口概述与HTTP规范
|
||||
- 请求体结构与字段约束(email、type)
|
||||
- 响应格式与错误码
|
||||
- 验证码生成、存储与过期策略(Redis)
|
||||
- 邮件服务集成(pkg/email)
|
||||
- 不同验证码类型(注册、重置密码、更换邮箱)的处理逻辑
|
||||
- 实际请求与响应示例
|
||||
- 安全注意事项(频率限制、邮箱格式)
|
||||
|
||||
## 项目结构
|
||||
/api/v1/auth/send-code 属于认证模块,位于 Gin 路由分组 /api/v1/auth 下,由处理器负责接收请求、绑定参数、调用服务层发送验证码,并通过 Redis 与邮件服务完成验证码的持久化与发送。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Client["客户端"] --> Router["Gin 路由<br/>/api/v1/auth/send-code"]
|
||||
Router --> Handler["处理器<br/>SendVerificationCode"]
|
||||
Handler --> Service["服务层<br/>SendVerificationCode/VerifyCode"]
|
||||
Service --> Redis["Redis 客户端<br/>存储验证码/频率限制"]
|
||||
Service --> Email["邮件服务<br/>发送验证码邮件"]
|
||||
Email --> SMTP["SMTP 服务器"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
|
||||
## 核心组件
|
||||
- 路由与处理器
|
||||
- 路由注册:/api/v1/auth/send-code 绑定到 SendVerificationCode 处理器。
|
||||
- 处理器职责:参数绑定、调用服务层发送验证码、记录日志、返回统一响应。
|
||||
- 服务层
|
||||
- 生成6位数字验证码;按 type 与 email 组合键存储至 Redis,设置过期时间;设置发送频率限制;调用邮件服务发送对应类型的邮件。
|
||||
- Redis
|
||||
- 提供 Set/Get/Del/Exists 等基础操作,封装过期时间控制与错误处理。
|
||||
- 邮件服务
|
||||
- 基于 SMTP 的邮件发送,支持 465(隐式 TLS)与 587(显式 TLS)端口;根据 type 选择不同主题与正文模板。
|
||||
- 类型定义
|
||||
- SendVerificationCodeRequest 包含 email 与 type 字段,type 限定为 register/reset_password/change_email。
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L24)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [common.go](file://internal/types/common.go#L49-L54)
|
||||
|
||||
## 架构总览
|
||||
发送验证码的端到端流程如下:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant H as "处理器<br/>SendVerificationCode"
|
||||
participant S as "服务层<br/>SendVerificationCode/VerifyCode"
|
||||
participant R as "Redis 客户端"
|
||||
participant E as "邮件服务<br/>SendVerificationCode"
|
||||
participant M as "SMTP 服务器"
|
||||
C->>H : POST /api/v1/auth/send-code<br/>{email, type}
|
||||
H->>H : 绑定请求体并校验
|
||||
H->>S : SendVerificationCode(ctx, redis, email, type)
|
||||
S->>R : Exists(rate_limit_key)
|
||||
alt 已存在
|
||||
S-->>H : 返回“发送过于频繁”
|
||||
H-->>C : 400 错误
|
||||
else 不存在
|
||||
S->>S : 生成6位数字验证码
|
||||
S->>R : Set(code_key, code, 10分钟)
|
||||
S->>R : Set(rate_limit_key, 1, 1分钟)
|
||||
S->>E : 根据type发送邮件
|
||||
E->>M : 发送邮件
|
||||
M-->>E : 成功/失败
|
||||
alt 邮件发送失败
|
||||
S->>R : Del(code_key)
|
||||
S-->>H : 返回“发送邮件失败”
|
||||
H-->>C : 400 错误
|
||||
else 成功
|
||||
S-->>H : 返回成功
|
||||
H-->>C : 200 成功
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### HTTP 端点定义
|
||||
- 方法:POST
|
||||
- 路径:/api/v1/auth/send-code
|
||||
- 功能:根据邮箱与类型发送验证码邮件,并在 Redis 中存储验证码及频率限制。
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
|
||||
### 请求体结构
|
||||
- 字段
|
||||
- email: 必填,需符合邮箱格式
|
||||
- type: 必填,枚举值为 register/reset_password/change_email
|
||||
- 参数绑定与校验
|
||||
- 使用 Gin 的绑定与验证机制,确保 email 符合邮箱格式,type 在允许范围内。
|
||||
|
||||
章节来源
|
||||
- [common.go](file://internal/types/common.go#L49-L54)
|
||||
|
||||
### 响应格式
|
||||
- 成功
|
||||
- 状态码:200
|
||||
- 结构:统一响应体,包含 message 字段提示“验证码已发送,请查收邮件”
|
||||
- 失败
|
||||
- 状态码:400
|
||||
- 结构:统一错误响应体,包含错误码与错误信息
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
|
||||
### 错误码与错误场景
|
||||
- 400 参数错误
|
||||
- 请求体绑定失败或参数校验失败
|
||||
- 400 发送过于频繁
|
||||
- Redis 中存在频率限制键(1分钟内)
|
||||
- 400 邮件发送失败
|
||||
- 邮件服务未启用或 SMTP 发送异常
|
||||
- 400 验证码已过期或不存在
|
||||
- 验证码校验时 Redis 中无对应键
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
|
||||
### 验证码生成与存储(Redis)
|
||||
- 生成规则
|
||||
- 6位数字验证码
|
||||
- 存储键
|
||||
- 验证码键:verification:code:{type}:{email}
|
||||
- 过期时间:10分钟
|
||||
- 频率限制
|
||||
- 频率限制键:verification:rate_limit:{type}:{email}
|
||||
- 过期时间:1分钟
|
||||
- Redis 操作
|
||||
- Set/SetEx:写入验证码与频率限制
|
||||
- Get:读取验证码用于校验
|
||||
- Del:验证成功后删除验证码键
|
||||
- Exists:检查是否处于发送冷却
|
||||
|
||||
章节来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L24)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
|
||||
### 邮件服务集成(pkg/email)
|
||||
- 初始化
|
||||
- 通过全局初始化函数完成一次性初始化,随后通过 MustGetService 获取实例
|
||||
- 发送逻辑
|
||||
- 根据 type 选择不同主题与正文模板
|
||||
- 支持 465(隐式 TLS)与 587(显式 TLS)两种端口模式
|
||||
- 当邮件服务未启用时,返回“邮件服务未启用”的错误
|
||||
- 主题与正文
|
||||
- 注册:邮箱验证
|
||||
- 重置密码:重置密码
|
||||
- 更换邮箱:更换邮箱验证
|
||||
- 默认:通用验证码
|
||||
|
||||
章节来源
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [manager.go](file://pkg/email/manager.go#L1-L43)
|
||||
- [main.go](file://cmd/server/main.go#L71-L74)
|
||||
|
||||
### 不同验证码类型的处理逻辑
|
||||
- 注册(register)
|
||||
- 邮件主题:邮箱验证
|
||||
- 通常配合注册接口使用,注册时需提供验证码
|
||||
- 重置密码(reset_password)
|
||||
- 邮件主题:重置密码
|
||||
- 与 /api/v1/auth/reset-password 配合使用
|
||||
- 更换邮箱(change_email)
|
||||
- 邮件主题:更换邮箱验证
|
||||
- 与用户更换邮箱流程配合使用
|
||||
- 默认(其他)
|
||||
- 通用验证码主题
|
||||
|
||||
章节来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L106-L118)
|
||||
- [email.go](file://pkg/email/email.go#L107-L139)
|
||||
|
||||
### 安全考虑
|
||||
- 邮箱格式验证
|
||||
- 请求体中 email 字段使用邮箱格式校验
|
||||
- 发送频率限制
|
||||
- Redis 中按 type+email 维度设置1分钟冷却,避免刷屏
|
||||
- 验证码有效期
|
||||
- Redis 中验证码设置10分钟过期,过期即失效
|
||||
- 重复使用防护
|
||||
- 验证码校验成功后立即删除键,防止二次使用
|
||||
- 邮件服务开关
|
||||
- 若未启用邮件服务,发送验证码会直接失败,避免泄露敏感信息
|
||||
|
||||
章节来源
|
||||
- [common.go](file://internal/types/common.go#L49-L54)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
- [email.go](file://pkg/email/email.go#L29-L40)
|
||||
|
||||
## 依赖关系分析
|
||||
- 处理器依赖服务层
|
||||
- 服务层依赖 Redis 与邮件服务
|
||||
- 邮件服务依赖配置与日志
|
||||
- Redis 客户端依赖配置与日志
|
||||
- 全局初始化顺序:配置 -> 日志 -> 数据库 -> JWT -> Redis -> 对象存储 -> 邮件服务
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
H["处理器<br/>auth_handler.go"] --> S["服务层<br/>verification_service.go"]
|
||||
S --> R["Redis 客户端<br/>redis.go"]
|
||||
S --> E["邮件服务<br/>email.go"]
|
||||
E --> Cfg["配置<br/>config.go"]
|
||||
E --> Lg["日志"]
|
||||
R --> Cfg
|
||||
R --> Lg
|
||||
Main["服务启动<br/>main.go"] --> E
|
||||
Main --> R
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [config.go](file://pkg/config/config.go#L49-L107)
|
||||
- [main.go](file://cmd/server/main.go#L27-L74)
|
||||
|
||||
章节来源
|
||||
- [main.go](file://cmd/server/main.go#L27-L74)
|
||||
|
||||
## 性能考量
|
||||
- Redis 操作均为 O(1),Set/Get/Del/Exists 均为常数时间复杂度
|
||||
- 验证码长度固定为6位,生成与比较成本低
|
||||
- 邮件发送为外部依赖,受网络与SMTP服务器性能影响
|
||||
- 建议
|
||||
- 合理设置 Redis 连接池大小(PoolSize)
|
||||
- 控制邮件发送并发,避免瞬时高峰导致SMTP限流
|
||||
- 对高频请求开启更严格的频率限制(如增加冷却时间)
|
||||
|
||||
[本节为通用性能建议,不直接分析具体文件]
|
||||
|
||||
## 故障排查指南
|
||||
- 400 参数错误
|
||||
- 检查请求体是否包含 email 与 type,且 type 是否在允许范围内
|
||||
- 400 发送过于频繁
|
||||
- 等待1分钟冷却时间,或检查 Redis 中 rate_limit 键是否仍存在
|
||||
- 400 邮件发送失败
|
||||
- 确认邮件服务已启用(EMAIL_ENABLED=true)
|
||||
- 检查 SMTP 配置(主机、端口、用户名、密码、发件人名称)
|
||||
- 查看日志中 SMTP 发送错误信息
|
||||
- 400 验证码已过期或不存在
|
||||
- 检查 Redis 中 code 键是否存在与过期时间
|
||||
- 确认验证码是否已被验证成功后删除
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L118)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||||
|
||||
## 结论
|
||||
/api/v1/auth/send-code 端点通过 Gin 处理器接收请求,调用服务层完成验证码生成、Redis 存储与频率限制、邮件发送等流程。其设计遵循最小暴露面原则:严格参数校验、冷却时间、过期时间与删除机制共同保障安全性与可用性。结合 pkg/email 与 pkg/redis 的稳定实现,整体具备良好的扩展性与可维护性。
|
||||
|
||||
[本节为总结性内容,不直接分析具体文件]
|
||||
|
||||
## 附录
|
||||
|
||||
### 请求与响应示例
|
||||
- 请求示例
|
||||
- 方法:POST
|
||||
- 路径:/api/v1/auth/send-code
|
||||
- 请求体:
|
||||
- email: user@example.com
|
||||
- type: register 或 reset_password 或 change_email
|
||||
- 成功响应示例
|
||||
- 状态码:200
|
||||
- 响应体:包含 message 字段,提示“验证码已发送,请查收邮件”
|
||||
- 失败响应示例
|
||||
- 状态码:400
|
||||
- 响应体:包含错误码与错误信息,如“发送过于频繁,请稍后再试”或“发送邮件失败”
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [common.go](file://internal/types/common.go#L49-L54)
|
||||
352
.qoder/repowiki/zh/content/API参考/认证API/用户注册.md
Normal file
352
.qoder/repowiki/zh/content/API参考/认证API/用户注册.md
Normal file
@@ -0,0 +1,352 @@
|
||||
# 用户注册
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go)
|
||||
- [routes.go](file://internal/handler/routes.go)
|
||||
- [common.go](file://internal/types/common.go)
|
||||
- [response.go](file://internal/model/response.go)
|
||||
- [user_service.go](file://internal/service/user_service.go)
|
||||
- [verification_service.go](file://internal/service/verification_service.go)
|
||||
- [password.go](file://pkg/auth/password.go)
|
||||
- [user.go](file://internal/model/user.go)
|
||||
- [auth_handler_test.go](file://internal/handler/auth_handler_test.go)
|
||||
- [common_test.go](file://internal/types/common_test.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能与扩展性](#性能与扩展性)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向“用户注册”API,围绕 /api/v1/auth/register 端点进行完整说明。内容覆盖:
|
||||
- HTTP 方法与路由
|
||||
- 请求体字段与校验规则
|
||||
- 响应格式与错误码
|
||||
- 验证码机制与防暴力注册策略
|
||||
- 密码加密存储流程
|
||||
- 安全建议(密码强度、邮箱格式、防暴力注册)
|
||||
|
||||
## 项目结构
|
||||
该功能由 Handler 层接收请求、Service 层执行业务逻辑、Model 层承载数据模型,并通过 JWT 生成登录令牌;验证码由 Redis 缓存并在邮件服务中发送。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Client["客户端"] --> Routes["路由: /api/v1/auth/register"]
|
||||
Routes --> Handler["处理器: Register"]
|
||||
Handler --> VerifyCode["验证码校验: VerifyCode"]
|
||||
Handler --> UserService["服务: RegisterUser"]
|
||||
UserService --> Password["密码加密: HashPassword"]
|
||||
UserService --> ModelUser["用户模型: User"]
|
||||
UserService --> JWT["JWT 服务: GenerateToken"]
|
||||
Handler --> Response["统一响应: Response/ErrorResponse"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L84)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L68)
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
|
||||
## 核心组件
|
||||
- 路由与入口
|
||||
- 路由位于 v1 组下的 /auth/register,无需 JWT 即可访问。
|
||||
- 请求体与校验
|
||||
- 请求体字段:username、email、password、avatar、verification_code。
|
||||
- 校验规则:必填、长度/格式约束、验证码长度固定为6。
|
||||
- 业务处理
|
||||
- 验证码校验通过后,检查用户名/邮箱唯一性,加密密码,创建用户并生成 JWT。
|
||||
- 响应与错误
|
||||
- 成功返回包含 token 与用户信息的结构化响应;常见错误包括参数错误、验证码错误、用户名/邮箱已存在等。
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L84)
|
||||
- [common.go](file://internal/types/common.go#L33-L40)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L68)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
|
||||
## 架构总览
|
||||
注册流程的端到端调用序列如下:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant R as "路由"
|
||||
participant H as "处理器 : Register"
|
||||
participant VS as "验证码服务 : VerifyCode"
|
||||
participant US as "用户服务 : RegisterUser"
|
||||
participant PS as "密码服务 : HashPassword"
|
||||
participant M as "用户模型 : User"
|
||||
participant JS as "JWT服务 : GenerateToken"
|
||||
participant RESP as "响应"
|
||||
C->>R : POST /api/v1/auth/register
|
||||
R->>H : 转发请求
|
||||
H->>H : 解析并绑定请求体
|
||||
H->>VS : 校验邮箱验证码
|
||||
VS-->>H : 验证通过/失败
|
||||
alt 验证失败
|
||||
H-->>RESP : 返回400错误
|
||||
else 验证通过
|
||||
H->>US : 调用注册流程
|
||||
US->>US : 检查用户名/邮箱唯一性
|
||||
US->>PS : 加密密码
|
||||
PS-->>US : 密文
|
||||
US->>M : 创建用户记录
|
||||
US->>JS : 生成JWT
|
||||
JS-->>US : token
|
||||
US-->>H : 返回用户与token
|
||||
H-->>RESP : 返回200成功响应
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L27-L84)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L68)
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 接口定义与请求体
|
||||
- 端点:POST /api/v1/auth/register
|
||||
- 请求体字段
|
||||
- username:必填,长度3~50
|
||||
- email:必填,邮箱格式
|
||||
- password:必填,长度6~128
|
||||
- avatar:可选,URL格式
|
||||
- verification_code:必填,长度6
|
||||
- 响应
|
||||
- 成功:返回包含 token 与用户信息的结构化响应
|
||||
- 失败:返回统一错误响应,包含业务码与消息
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L84)
|
||||
- [common.go](file://internal/types/common.go#L33-L40)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
|
||||
### 验证码机制与防暴力注册
|
||||
- 验证码生成与存储
|
||||
- 生成6位数字验证码,有效期10分钟,发送频率限制1分钟。
|
||||
- 存储于 Redis,键命名包含类型与邮箱。
|
||||
- 验证流程
|
||||
- 校验验证码是否存在且一致,一致即删除该验证码。
|
||||
- 防暴力注册
|
||||
- 发送频率限制键存在即拒绝重复发送,降低刷验证码风险。
|
||||
- 注册接口对用户名/邮箱唯一性检查,避免重复注册。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["开始"]) --> Gen["生成6位验证码"]
|
||||
Gen --> Store["写入Redis: 验证码键(10分钟)"]
|
||||
Store --> RateLimit["写入Redis: 发送频率限制键(1分钟)"]
|
||||
RateLimit --> Email["发送邮件"]
|
||||
Email --> Verify["校验验证码"]
|
||||
Verify --> Match{"是否匹配?"}
|
||||
Match --> |否| Expired["返回错误: 验证码错误/过期"]
|
||||
Match --> |是| Del["删除验证码键"]
|
||||
Del --> Done(["结束"])
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L26-L98)
|
||||
|
||||
章节来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L24)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L77)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
|
||||
### 密码加密与存储
|
||||
- 加密方式:bcrypt,默认成本
|
||||
- 存储:用户密码以密文形式保存,不返回明文
|
||||
- 登录校验:使用 bcrypt 对比哈希
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
In(["输入明文密码"]) --> Hash["bcrypt加密"]
|
||||
Hash --> Out(["返回密文"])
|
||||
Out --> Store["持久化存储"]
|
||||
Store --> Login["登录时对比哈希"]
|
||||
Login --> Ok["匹配成功"]
|
||||
Login --> Fail["匹配失败"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user_service.go](file://internal/service/user_service.go#L32-L36)
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
|
||||
章节来源
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user_service.go](file://internal/service/user_service.go#L32-L36)
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
|
||||
### 用户模型与唯一性约束
|
||||
- 用户模型包含:id、username、password、email、avatar、points、role、status、属性、登录时间、创建/更新时间等
|
||||
- 唯一性约束:username 与 email 在数据库层面唯一索引
|
||||
- 注册时:若用户名或邮箱已存在,返回错误
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER {
|
||||
bigint id PK
|
||||
varchar username UK
|
||||
varchar password
|
||||
varchar email UK
|
||||
varchar avatar
|
||||
integer points
|
||||
varchar role
|
||||
smallint status
|
||||
jsonb properties
|
||||
timestamp last_login_at
|
||||
timestamp created_at
|
||||
timestamp updated_at
|
||||
}
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
|
||||
章节来源
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
- [user_service.go](file://internal/service/user_service.go#L14-L31)
|
||||
|
||||
### 错误码与响应格式
|
||||
- 成功:200,返回结构化响应,包含 token 与用户信息
|
||||
- 参数错误:400,请求体绑定失败或字段校验失败
|
||||
- 验证码错误:400,验证码不存在/过期/不匹配
|
||||
- 资源冲突:409,用户名或邮箱已存在
|
||||
- 服务器错误:500,内部异常
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L27-L84)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
- [user_service.go](file://internal/service/user_service.go#L14-L31)
|
||||
|
||||
### 安全考虑与最佳实践
|
||||
- 密码强度
|
||||
- 至少6位,建议结合复杂度策略(字母、数字、特殊字符)
|
||||
- 使用 bcrypt 存储,避免明文或弱加密
|
||||
- 邮箱格式验证
|
||||
- 使用框架内置邮箱格式校验
|
||||
- 防暴力注册
|
||||
- 验证码发送频率限制(1分钟)
|
||||
- 验证码有效期(10分钟),过期自动失效
|
||||
- 唯一性检查防止重复注册
|
||||
- 传输安全
|
||||
- 建议启用 HTTPS,避免明文传输
|
||||
- 日志与审计
|
||||
- 记录注册失败与异常行为,便于追踪
|
||||
|
||||
章节来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L24)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L77)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [user_service.go](file://internal/service/user_service.go#L14-L31)
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
|
||||
## 依赖关系分析
|
||||
- 处理器依赖
|
||||
- 验证码服务:用于校验注册验证码
|
||||
- 用户服务:执行注册流程(唯一性检查、密码加密、创建用户、生成JWT)
|
||||
- JWT 服务:生成登录令牌
|
||||
- 服务依赖
|
||||
- 密码服务:bcrypt 加密与校验
|
||||
- 数据模型:用户实体
|
||||
- 工具与中间件
|
||||
- 路由:定义 /api/v1/auth/register
|
||||
- 统一响应:封装业务码与消息
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Handler["处理器: Register"] --> VS["验证码服务: VerifyCode"]
|
||||
Handler --> US["用户服务: RegisterUser"]
|
||||
US --> PS["密码服务: HashPassword"]
|
||||
US --> Model["用户模型: User"]
|
||||
US --> JWT["JWT服务: GenerateToken"]
|
||||
Handler --> Resp["统一响应: Response/ErrorResponse"]
|
||||
Route["路由: /api/v1/auth/register"] --> Handler
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L27-L84)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L68)
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L27-L84)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L68)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user.go](file://internal/model/user.go#L7-L21)
|
||||
- [response.go](file://internal/model/response.go#L20-L73)
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
|
||||
## 性能与扩展性
|
||||
- 验证码缓存
|
||||
- Redis 存储验证码与频率限制,具备高并发与低延迟特性
|
||||
- 密码加密
|
||||
- bcrypt 默认成本在安全性与性能间平衡,可根据硬件能力调整
|
||||
- 扩展建议
|
||||
- 引入速率限制中间件,对 /api/v1/auth/register 进一步限流
|
||||
- 增加 IP/设备维度的风控策略
|
||||
- 对高频失败场景增加验证码挑战或人机验证
|
||||
|
||||
[本节为通用建议,不直接分析具体文件]
|
||||
|
||||
## 故障排查指南
|
||||
- 常见错误与定位
|
||||
- 参数错误:检查请求体字段是否满足长度/格式要求
|
||||
- 验证码错误:确认验证码是否过期、是否与发送邮箱一致
|
||||
- 用户名/邮箱已存在:检查数据库唯一性约束
|
||||
- 单元测试参考
|
||||
- 注册请求体校验、错误处理与响应格式可通过测试用例验证
|
||||
|
||||
章节来源
|
||||
- [auth_handler_test.go](file://internal/handler/auth_handler_test.go#L74-L116)
|
||||
- [common_test.go](file://internal/types/common_test.go#L215-L287)
|
||||
|
||||
## 结论
|
||||
用户注册 API 通过严格的请求体校验、验证码机制与 bcrypt 密码加密,提供了基础的安全保障。配合唯一性检查与频率限制,能够有效降低重复注册与暴力注册的风险。建议在生产环境中进一步完善风控策略与监控告警体系。
|
||||
|
||||
[本节为总结性内容,不直接分析具体文件]
|
||||
|
||||
## 附录
|
||||
|
||||
### 请求与响应示例(路径引用)
|
||||
- 请求体字段与校验规则
|
||||
- 字段定义与校验规则参见:[请求体定义](file://internal/types/common.go#L33-L40)
|
||||
- 成功响应结构
|
||||
- 成功响应结构参见:[统一响应](file://internal/model/response.go#L20-L73)
|
||||
- 登录响应结构参见:[登录响应](file://internal/types/common.go#L107-L126)
|
||||
- 错误响应结构
|
||||
- 错误响应结构参见:[错误响应](file://internal/model/response.go#L20-L73)
|
||||
- 路由与端点
|
||||
- 注册路由参见:[路由定义](file://internal/handler/routes.go#L16-L26)
|
||||
- 处理器与业务流程
|
||||
- 注册处理器参见:[注册处理器](file://internal/handler/auth_handler.go#L27-L84)
|
||||
- 注册业务流程参见:[注册服务](file://internal/service/user_service.go#L12-L68)
|
||||
- 验证码与防暴力
|
||||
- 验证码生成与校验参见:[验证码服务](file://internal/service/verification_service.go#L26-L98)
|
||||
- 密码加密
|
||||
- 密码加密与校验参见:[密码服务](file://pkg/auth/password.go#L7-L21)
|
||||
351
.qoder/repowiki/zh/content/API参考/认证API/用户登录.md
Normal file
351
.qoder/repowiki/zh/content/API参考/认证API/用户登录.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# 用户登录
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go)
|
||||
- [routes.go](file://internal/handler/routes.go)
|
||||
- [jwt.go](file://pkg/auth/jwt.go)
|
||||
- [password.go](file://pkg/auth/password.go)
|
||||
- [user_service.go](file://internal/service/user_service.go)
|
||||
- [common.go](file://internal/types/common.go)
|
||||
- [response.go](file://internal/model/response.go)
|
||||
- [user.go](file://internal/model/user.go)
|
||||
- [token.go](file://internal/model/token.go)
|
||||
- [token_service.go](file://internal/service/token_service.go)
|
||||
- [auth.go](file://internal/middleware/auth.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向“用户登录”API,围绕 /api/v1/auth/login 端点进行完整说明,覆盖:
|
||||
- HTTP 方法与路由
|
||||
- 请求体结构(用户名或邮箱登录)
|
||||
- 响应格式(包含JWT token与用户信息)
|
||||
- 错误码与错误处理
|
||||
- JWT令牌生成流程(访问令牌与声明)
|
||||
- 登录成功/失败后的审计日志记录(IP、User-Agent)
|
||||
- 安全建议(防暴力破解、错误提示模糊化)
|
||||
|
||||
## 项目结构
|
||||
该登录流程涉及以下模块协作:
|
||||
- 路由层:注册 /api/v1/auth/login 路由
|
||||
- 控制器层:处理登录请求、参数校验、调用服务层
|
||||
- 服务层:用户查找、密码校验、令牌生成、登录日志记录
|
||||
- 认证与密码:JWT服务、bcrypt密码加解密
|
||||
- 数据模型:用户、登录日志、令牌
|
||||
- 中间件:JWT认证中间件用于后续受保护接口
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Client["客户端"] --> Routes["路由注册<br/>/api/v1/auth/login"]
|
||||
Routes --> Handler["控制器 Login()<br/>参数绑定/错误处理"]
|
||||
Handler --> Service["服务层 LoginUser()<br/>查找用户/校验密码/生成JWT"]
|
||||
Service --> JWT["JWT服务 GenerateToken()<br/>签发访问令牌"]
|
||||
Service --> ModelUser["用户模型 User"]
|
||||
Service --> ModelLog["登录日志 UserLoginLog"]
|
||||
Handler --> Resp["统一响应 Response/ErrorResponse"]
|
||||
Client --> Middleware["认证中间件 AuthMiddleware()<br/>Bearer Token 校验"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [user.go](file://internal/model/user.go#L1-L21)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
|
||||
## 核心组件
|
||||
- 路由与控制器
|
||||
- /api/v1/auth/login 由控制器 Login 处理,负责参数绑定、IP/User-Agent采集、调用服务层并返回统一响应。
|
||||
- 服务层
|
||||
- LoginUser 支持用户名或邮箱登录;校验用户状态与密码;生成JWT;更新最后登录时间;记录成功/失败日志。
|
||||
- 认证与密码
|
||||
- JWT服务提供 GenerateToken/ValidateToken;密码使用 bcrypt 进行哈希与校验。
|
||||
- 数据模型
|
||||
- User:用户信息;UserLoginLog:登录审计日志;Token:令牌模型(用于后续刷新/失效等场景)。
|
||||
- 统一响应
|
||||
- Response/ErrorResponse 提供统一的状态码与消息封装。
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [password.go](file://pkg/auth/password.go#L7-L21)
|
||||
- [user.go](file://internal/model/user.go#L1-L21)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
- [token.go](file://internal/model/token.go#L1-L15)
|
||||
- [response.go](file://internal/model/response.go#L20-L53)
|
||||
|
||||
## 架构总览
|
||||
登录端到端序列图(POST /api/v1/auth/login):
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant R as "路由"
|
||||
participant H as "控制器 Login()"
|
||||
participant S as "服务层 LoginUser()"
|
||||
participant J as "JWT服务"
|
||||
participant U as "用户模型"
|
||||
participant L as "登录日志"
|
||||
C->>R : "POST /api/v1/auth/login"
|
||||
R->>H : "进入 Login 控制器"
|
||||
H->>H : "ShouldBindJSON 绑定请求体"
|
||||
H->>S : "LoginUser(jwtService, username, password, ip, ua)"
|
||||
S->>U : "根据用户名或邮箱查找用户"
|
||||
S->>S : "校验用户状态"
|
||||
S->>S : "bcrypt 校验密码"
|
||||
S->>J : "GenerateToken(userID, username, role)"
|
||||
J-->>S : "返回JWT字符串"
|
||||
S->>U : "更新 last_login_at"
|
||||
S->>L : "logSuccessLogin/logFailedLogin"
|
||||
S-->>H : "返回 user, token"
|
||||
H-->>C : "200 成功响应或401失败响应"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [user.go](file://internal/model/user.go#L1-L21)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 接口定义与请求/响应
|
||||
- HTTP 方法与路径
|
||||
- 方法:POST
|
||||
- 路径:/api/v1/auth/login
|
||||
- 请求体结构
|
||||
- 字段:username(支持用户名或邮箱)、password(6-128字符)
|
||||
- 参数校验:必填、长度约束
|
||||
- 响应格式
|
||||
- 成功:统一响应,data 包含 token 与 userInfo
|
||||
- 失败:统一错误响应,包含 code 与 message
|
||||
- 错误码
|
||||
- 400:请求参数错误
|
||||
- 401:未授权(用户名/邮箱或密码错误、账号被禁用等)
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [common.go](file://internal/types/common.go#L27-L31)
|
||||
- [response.go](file://internal/model/response.go#L20-L53)
|
||||
|
||||
### 请求体结构与参数校验
|
||||
- 请求体字段
|
||||
- username:支持用户名或邮箱
|
||||
- password:6-128字符
|
||||
- 参数校验
|
||||
- Gin 绑定时会触发结构体 tag 校验(必填、长度范围)
|
||||
- 实际行为
|
||||
- 控制器层在绑定失败时直接返回400
|
||||
|
||||
章节来源
|
||||
- [common.go](file://internal/types/common.go#L27-L31)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L101-L109)
|
||||
|
||||
### 登录流程与JWT生成
|
||||
- 登录流程要点
|
||||
- 识别登录方式:包含@视为邮箱,否则为用户名
|
||||
- 校验用户状态(仅状态为正常才允许登录)
|
||||
- 使用 bcrypt 校验密码
|
||||
- 生成JWT访问令牌(包含用户ID、用户名、角色等声明)
|
||||
- 更新最后登录时间
|
||||
- 记录登录日志(成功/失败均记录IP与User-Agent)
|
||||
- JWT声明内容
|
||||
- 包含 user_id、username、role
|
||||
- 默认包含过期时间、签发时间、生效时间、签发者等注册声明
|
||||
- 令牌有效期
|
||||
- 由JWT服务配置的过期小时数决定
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入 LoginUser"]) --> Detect["判断登录方式<br/>用户名或邮箱"]
|
||||
Detect --> FindUser["查找用户"]
|
||||
FindUser --> Status{"用户状态正常?"}
|
||||
Status -- 否 --> LogFail["记录失败日志<br/>原因:账号被禁用"]
|
||||
LogFail --> ReturnErr["返回错误"]
|
||||
Status -- 是 --> CheckPwd["bcrypt 校验密码"]
|
||||
CheckPwd --> PwdOK{"密码正确?"}
|
||||
PwdOK -- 否 --> LogFail2["记录失败日志<br/>原因:密码错误"]
|
||||
LogFail2 --> ReturnErr
|
||||
PwdOK -- 是 --> GenToken["GenerateToken(userID, username, role)"]
|
||||
GenToken --> UpdateTime["更新 last_login_at"]
|
||||
UpdateTime --> LogSuccess["记录成功日志"]
|
||||
LogSuccess --> Done(["返回 user, token"])
|
||||
ReturnErr --> Done
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [password.go](file://pkg/auth/password.go#L16-L21)
|
||||
- [user.go](file://internal/model/user.go#L1-L21)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
|
||||
章节来源
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [password.go](file://pkg/auth/password.go#L16-L21)
|
||||
|
||||
### 响应格式与错误码
|
||||
- 成功响应
|
||||
- data:包含 token 与 userInfo(id、username、email、avatar、points、role、status、last_login_at、created_at、updated_at)
|
||||
- 失败响应
|
||||
- 400:请求参数错误
|
||||
- 401:未授权(用户名/邮箱或密码错误、账号被禁用)
|
||||
- 统一响应封装
|
||||
- Response/ErrorResponse 提供 code、message、data/error 字段
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L131-L147)
|
||||
- [common.go](file://internal/types/common.go#L107-L126)
|
||||
- [response.go](file://internal/model/response.go#L20-L53)
|
||||
|
||||
### 登录日志记录(IP、User-Agent)
|
||||
- 记录内容
|
||||
- 成功/失败均记录:用户ID、IP地址、User-Agent、登录方式(PASSWORD)、是否成功、失败原因
|
||||
- 记录时机
|
||||
- 成功:登录成功后记录
|
||||
- 失败:用户不存在、账号禁用、密码错误等情况下记录
|
||||
- 存储位置
|
||||
- 写入 user_login_logs 表
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L111-L129)
|
||||
- [user_service.go](file://internal/service/user_service.go#L203-L226)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
|
||||
### 安全考虑与建议
|
||||
- 防暴力破解
|
||||
- 建议在网关或应用层增加速率限制(例如基于IP或用户名的限流),在失败时延长冷却时间或临时封禁
|
||||
- 可结合验证码机制(当前登录接口未强制验证码,但注册/重置密码有验证码流程)
|
||||
- 错误提示模糊化
|
||||
- 当前服务层对“用户不存在/密码错误/账号禁用”均返回统一的“用户名/邮箱或密码错误”,避免泄露具体原因
|
||||
- 令牌管理
|
||||
- 当前登录仅返回JWT访问令牌;若需刷新令牌,可参考后续令牌服务(刷新/失效等)能力
|
||||
- 传输安全
|
||||
- 建议仅在HTTPS下提供登录接口,防止凭据被窃听
|
||||
|
||||
章节来源
|
||||
- [user_service.go](file://internal/service/user_service.go#L88-L103)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L116-L129)
|
||||
|
||||
## 依赖关系分析
|
||||
- 控制器依赖
|
||||
- 控制器 Login 依赖:JWT服务、日志、Redis(注册流程)、服务层 LoginUser
|
||||
- 服务层依赖
|
||||
- LoginUser 依赖:用户仓库(查找用户)、JWT服务(生成令牌)、密码工具(bcrypt)、登录日志仓库(写入日志)
|
||||
- 认证依赖
|
||||
- JWT服务依赖:golang-jwt库;密码工具依赖:bcrypt
|
||||
- 模型依赖
|
||||
- User、UserLoginLog、Token 模型用于数据持久化与审计
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
H["控制器 Login()"] --> S["服务层 LoginUser()"]
|
||||
H --> J["JWT服务 GenerateToken()"]
|
||||
S --> U["User 模型"]
|
||||
S --> L["UserLoginLog 模型"]
|
||||
S --> P["bcrypt 密码校验"]
|
||||
H --> R["路由 RegisterRoutes()"]
|
||||
M["认证中间件 AuthMiddleware()"] --> J
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [password.go](file://pkg/auth/password.go#L16-L21)
|
||||
- [user.go](file://internal/model/user.go#L1-L21)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [password.go](file://pkg/auth/password.go#L16-L21)
|
||||
- [user.go](file://internal/model/user.go#L1-L21)
|
||||
- [user.go](file://internal/model/user.go#L52-L71)
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
|
||||
## 性能考量
|
||||
- 登录路径涉及数据库查询与密码校验,建议:
|
||||
- 对用户表建立合适的索引(username、email)
|
||||
- 密码校验使用 bcrypt,默认成本适中,可根据硬件能力调整
|
||||
- 登录日志写入采用异步或批量策略(当前为同步写入,注意高并发下的I/O影响)
|
||||
- JWT生成与校验为CPU密集度较低的操作,主要瓶颈在数据库与密码校验
|
||||
|
||||
## 故障排查指南
|
||||
- 常见问题与定位
|
||||
- 400 参数错误:检查请求体字段是否缺失或长度不符合要求
|
||||
- 401 未授权:核对用户名/邮箱是否存在、账号状态是否正常、密码是否正确
|
||||
- 登录日志未记录:确认日志写入是否成功,检查数据库连接与表结构
|
||||
- 日志与审计
|
||||
- 成功/失败日志均包含 IP 与 User-Agent,便于追踪来源设备与来源网络
|
||||
- 令牌相关
|
||||
- 若后续引入刷新令牌,可参考令牌服务中的刷新/失效逻辑
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L101-L129)
|
||||
- [user_service.go](file://internal/service/user_service.go#L203-L226)
|
||||
- [response.go](file://internal/model/response.go#L20-L53)
|
||||
|
||||
## 结论
|
||||
/api/v1/auth/login 提供了完整的用户名或邮箱登录能力,具备参数校验、密码校验、JWT签发与登录日志记录。当前实现聚焦于登录流程本身,后续可在速率限制、验证码、刷新令牌等方面进一步增强安全性与可用性。
|
||||
|
||||
## 附录
|
||||
|
||||
### API定义与示例
|
||||
|
||||
- 端点
|
||||
- 方法:POST
|
||||
- 路径:/api/v1/auth/login
|
||||
- 请求体
|
||||
- username:字符串,必填,支持用户名或邮箱
|
||||
- password:字符串,必填,长度6-128
|
||||
- 成功响应
|
||||
- code:200
|
||||
- data:包含 token 与 userInfo
|
||||
- 示例(结构示意)
|
||||
- data: { token: "...", userInfo: { id, username, email, avatar, points, role, status, last_login_at, created_at, updated_at } }
|
||||
- 失败响应
|
||||
- 400:请求参数错误
|
||||
- 401:未授权(用户名/邮箱或密码错误、账号被禁用)
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [common.go](file://internal/types/common.go#L27-L31)
|
||||
- [common.go](file://internal/types/common.go#L107-L126)
|
||||
- [response.go](file://internal/model/response.go#L20-L53)
|
||||
|
||||
### JWT声明与令牌生命周期
|
||||
- 声明内容
|
||||
- user_id、username、role
|
||||
- 过期时间、签发时间、生效时间、签发者等注册声明
|
||||
- 令牌类型
|
||||
- 当前登录返回访问令牌;刷新/失效等能力可参考令牌服务
|
||||
|
||||
章节来源
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L24-L53)
|
||||
- [token_service.go](file://internal/service/token_service.go#L151-L238)
|
||||
460
.qoder/repowiki/zh/content/API参考/认证API/认证API.md
Normal file
460
.qoder/repowiki/zh/content/API参考/认证API/认证API.md
Normal file
@@ -0,0 +1,460 @@
|
||||
# 认证API
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [routes.go](file://internal/handler/routes.go)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go)
|
||||
- [jwt.go](file://pkg/auth/jwt.go)
|
||||
- [password.go](file://pkg/auth/password.go)
|
||||
- [user_service.go](file://internal/service/user_service.go)
|
||||
- [verification_service.go](file://internal/service/verification_service.go)
|
||||
- [captcha_handler.go](file://internal/handler/captcha_handler.go)
|
||||
- [captcha_service.go](file://internal/service/captcha_service.go)
|
||||
- [auth.go](file://internal/middleware/auth.go)
|
||||
- [common.go](file://internal/types/common.go)
|
||||
- [email.go](file://pkg/email/email.go)
|
||||
- [config.go](file://pkg/config/config.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向开发者,系统性梳理认证API的设计与实现,覆盖用户注册、登录、发送验证码与重置密码四个核心端点。文档基于路由分组与处理器实现,详细说明每个API的HTTP方法、请求参数、响应格式与错误码;重点解释JWT认证机制在登录流程中的作用,以及验证码服务与邮箱服务的集成方式;并提供实际请求/响应示例路径,帮助快速理解认证流程。同时总结安全要点,包括密码加密存储、JWT过期策略与防暴力破解措施。
|
||||
|
||||
## 项目结构
|
||||
认证相关能力由“路由层-处理器层-服务层-基础设施层”四层构成:
|
||||
- 路由层:在统一的路由组下挂载认证相关端点
|
||||
- 处理器层:负责参数绑定、调用服务、组织响应与错误处理
|
||||
- 服务层:封装业务逻辑(用户注册/登录、验证码发送与校验、密码变更等)
|
||||
- 基础设施层:JWT签发与校验、密码加解密、Redis验证码存储、SMTP邮件发送
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "路由层"
|
||||
R["routes.go<br/>注册/auth路由组"]
|
||||
end
|
||||
subgraph "处理器层"
|
||||
AH["auth_handler.go<br/>注册/登录/发送验证码/重置密码"]
|
||||
CH["captcha_handler.go<br/>图形验证码生成/校验"]
|
||||
end
|
||||
subgraph "服务层"
|
||||
US["user_service.go<br/>注册/登录/密码重置等"]
|
||||
VS["verification_service.go<br/>验证码生成/发送/校验"]
|
||||
CS["captcha_service.go<br/>图形验证码生成/校验"]
|
||||
end
|
||||
subgraph "基础设施层"
|
||||
JWT["jwt.go<br/>JWT签发/校验"]
|
||||
PW["password.go<br/>bcrypt加解密"]
|
||||
EM["email.go<br/>SMTP邮件发送"]
|
||||
CFG["config.go<br/>JWT/邮件/Redis等配置"]
|
||||
end
|
||||
R --> AH
|
||||
R --> CH
|
||||
AH --> US
|
||||
AH --> VS
|
||||
CH --> CS
|
||||
US --> JWT
|
||||
US --> PW
|
||||
VS --> EM
|
||||
VS --> CFG
|
||||
CS --> CFG
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L249)
|
||||
- [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L122)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L119)
|
||||
- [captcha_service.go](file://internal/service/captcha_service.go#L18-L166)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L10-L71)
|
||||
- [password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [email.go](file://pkg/email/email.go#L15-L163)
|
||||
- [config.go](file://pkg/config/config.go#L67-L107)
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
|
||||
## 核心组件
|
||||
- 路由组与端点
|
||||
- /api/v1/auth/register:POST,注册
|
||||
- /api/v1/auth/login:POST,登录
|
||||
- /api/v1/auth/send-code:POST,发送验证码
|
||||
- /api/v1/auth/reset-password:POST,重置密码
|
||||
- 中间件
|
||||
- 认证中间件:对受保护资源进行JWT校验
|
||||
- 关键数据模型
|
||||
- 请求/响应结构体定义于类型模块,包含登录、注册、验证码发送与重置密码等请求体与响应体字段
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
- [common.go](file://internal/types/common.go#L27-L61)
|
||||
|
||||
## 架构总览
|
||||
认证API采用“路由-处理器-服务-基础设施”的分层设计,认证流程的关键交互如下:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant H as "处理器(auth_handler)"
|
||||
participant S as "服务(user_service/verification_service)"
|
||||
participant J as "JWT服务(pkg/auth)"
|
||||
participant E as "邮件服务(pkg/email)"
|
||||
participant R as "Redis"
|
||||
rect rgb(255,255,255)
|
||||
Note over C,H : 注册流程
|
||||
C->>H : POST /api/v1/auth/register
|
||||
H->>S : VerifyCode(验证码校验)
|
||||
S->>R : GET verification : code : register : email
|
||||
R-->>S : 验证码
|
||||
S-->>H : 校验通过
|
||||
H->>S : RegisterUser(创建用户+生成JWT)
|
||||
S->>J : GenerateToken(userID, username, role)
|
||||
J-->>S : token
|
||||
S-->>H : 用户信息+token
|
||||
H-->>C : 成功响应(包含token与用户信息)
|
||||
end
|
||||
rect rgb(255,255,255)
|
||||
Note over C,H : 登录流程
|
||||
C->>H : POST /api/v1/auth/login
|
||||
H->>S : LoginUser(用户名/邮箱+密码)
|
||||
S->>J : GenerateToken(userID, username, role)
|
||||
J-->>S : token
|
||||
S-->>H : 用户信息+token
|
||||
H-->>C : 成功响应(包含token与用户信息)
|
||||
end
|
||||
rect rgb(255,255,255)
|
||||
Note over C,H : 发送验证码流程
|
||||
C->>H : POST /api/v1/auth/send-code
|
||||
H->>S : SendVerificationCode(生成+存储+限流+发邮件)
|
||||
S->>R : SET verification : code : type : email
|
||||
S->>E : 发送邮件
|
||||
E-->>S : 发送结果
|
||||
S-->>H : 成功
|
||||
H-->>C : 成功响应
|
||||
end
|
||||
rect rgb(255,255,255)
|
||||
Note over C,H : 重置密码流程
|
||||
C->>H : POST /api/v1/auth/reset-password
|
||||
H->>S : VerifyCode(验证码校验)
|
||||
S->>R : GET verification : code : reset_password : email
|
||||
R-->>S : 验证码
|
||||
S-->>H : 校验通过
|
||||
H->>S : ResetUserPassword(更新密码)
|
||||
S-->>H : 成功
|
||||
H-->>C : 成功响应
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L249)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L122)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L40-L98)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
|
||||
- [email.go](file://pkg/email/email.go#L29-L55)
|
||||
- [config.go](file://pkg/config/config.go#L67-L107)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 路由与端点
|
||||
- 路由组
|
||||
- /api/v1/auth:认证相关端点
|
||||
- /api/v1/user:受JWT保护的用户资料端点(不在本次文档范围)
|
||||
- 端点清单
|
||||
- POST /api/v1/auth/register:注册
|
||||
- POST /api/v1/auth/login:登录
|
||||
- POST /api/v1/auth/send-code:发送验证码
|
||||
- POST /api/v1/auth/reset-password:重置密码
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L16-L25)
|
||||
|
||||
### 注册接口(POST /api/v1/auth/register)
|
||||
- 功能概述
|
||||
- 接收用户名、邮箱、密码、验证码与可选头像,校验验证码后创建用户并签发JWT
|
||||
- 请求参数
|
||||
- 字段:username、email、password、verification_code、avatar
|
||||
- 校验规则:用户名长度、邮箱格式、密码长度、验证码长度、头像URL格式
|
||||
- 响应格式
|
||||
- 成功:包含token与用户信息
|
||||
- 失败:错误码与错误信息
|
||||
- 错误码
|
||||
- 400:请求参数错误、验证码错误、用户名/邮箱已存在、密码加密失败、生成Token失败
|
||||
- 安全要点
|
||||
- 密码经bcrypt加密存储
|
||||
- 验证码有效期短且一次性使用(校验通过即删除)
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L84)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L68)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [common.go](file://internal/types/common.go#L33-L40)
|
||||
|
||||
### 登录接口(POST /api/v1/auth/login)
|
||||
- 功能概述
|
||||
- 支持用户名或邮箱登录,校验密码后签发JWT,并记录登录日志
|
||||
- 请求参数
|
||||
- 字段:username(支持用户名或邮箱)、password
|
||||
- 校验规则:必填、长度范围
|
||||
- 响应格式
|
||||
- 成功:包含token与用户信息
|
||||
- 失败:401未授权
|
||||
- 错误码
|
||||
- 400:请求参数错误
|
||||
- 401:用户名/邮箱或密码错误、账号被禁用
|
||||
- 安全要点
|
||||
- 密码使用bcrypt校验
|
||||
- 登录成功更新最后登录时间
|
||||
- 失败场景记录登录日志
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [password.go](file://pkg/auth/password.go#L16-L21)
|
||||
- [common.go](file://internal/types/common.go#L27-L31)
|
||||
|
||||
### 发送验证码接口(POST /api/v1/auth/send-code)
|
||||
- 功能概述
|
||||
- 根据邮箱与类型(注册/重置密码/更换邮箱)生成6位数字验证码,存储至Redis并按类型限流,随后通过SMTP发送邮件
|
||||
- 请求参数
|
||||
- 字段:email、type(枚举:register/reset_password/change_email)
|
||||
- 校验规则:邮箱格式、type枚举
|
||||
- 响应格式
|
||||
- 成功:通用成功响应
|
||||
- 失败:错误码与错误信息
|
||||
- 错误码
|
||||
- 400:请求参数错误、发送过于频繁、验证码已过期或不存在、验证码错误
|
||||
- 安全要点
|
||||
- 验证码有效期10分钟
|
||||
- 发送频率限制1分钟/次
|
||||
- 邮件服务可开关,未启用时跳过发送
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L119)
|
||||
- [email.go](file://pkg/email/email.go#L29-L55)
|
||||
- [common.go](file://internal/types/common.go#L49-L54)
|
||||
- [config.go](file://pkg/config/config.go#L67-L107)
|
||||
|
||||
### 重置密码接口(POST /api/v1/auth/reset-password)
|
||||
- 功能概述
|
||||
- 通过邮箱验证码校验后,更新用户密码
|
||||
- 请求参数
|
||||
- 字段:email、verification_code、new_password
|
||||
- 校验规则:邮箱格式、验证码长度、新密码长度
|
||||
- 响应格式
|
||||
- 成功:通用成功响应
|
||||
- 失败:400或500
|
||||
- 错误码
|
||||
- 400:请求参数错误、验证码错误
|
||||
- 500:内部错误(如用户不存在、密码加密失败)
|
||||
- 安全要点
|
||||
- 密码经bcrypt加密存储
|
||||
- 验证码一次性使用(校验通过即删除)
|
||||
|
||||
章节来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
- [user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [common.go](file://internal/types/common.go#L55-L61)
|
||||
|
||||
### JWT认证机制(登录流程)
|
||||
- 生成与签发
|
||||
- 登录成功后,服务层调用JWT服务生成token,包含用户ID、用户名、角色及标准声明(过期时间、签发时间等)
|
||||
- 校验与中间件
|
||||
- 中间件从Authorization头提取Bearer token并调用JWT服务校验,校验通过后将用户信息写入上下文
|
||||
- 过期策略
|
||||
- JWT过期小时数来自配置,默认值可通过环境变量设置
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant H as "处理器(Login)"
|
||||
participant S as "服务(LoginUser)"
|
||||
participant J as "JWT服务"
|
||||
participant M as "认证中间件"
|
||||
C->>H : POST /api/v1/auth/login
|
||||
H->>S : LoginUser(usernameOrEmail, password)
|
||||
S->>J : GenerateToken(userID, username, role)
|
||||
J-->>S : token
|
||||
S-->>H : 用户信息+token
|
||||
H-->>C : {token, user_info}
|
||||
Note over C,M : 访问受保护资源
|
||||
C->>M : 携带Authorization : Bearer token
|
||||
M->>J : ValidateToken(token)
|
||||
J-->>M : Claims
|
||||
M-->>C : 放行
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
|
||||
- [user_service.go](file://internal/service/user_service.go#L70-L122)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L32-L71)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
- [config.go](file://pkg/config/config.go#L67-L71)
|
||||
|
||||
章节来源
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L10-L71)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
- [config.go](file://pkg/config/config.go#L67-L71)
|
||||
|
||||
### 验证码服务与邮箱服务集成
|
||||
- 验证码生成与存储
|
||||
- 生成6位数字验证码,存储于Redis,键名包含类型与邮箱,有效期10分钟
|
||||
- 发送频率限制1分钟/次,避免刷屏
|
||||
- 邮件发送
|
||||
- 根据类型选择不同主题与正文模板,支持465/587端口TLS/STARTTLS
|
||||
- 邮件服务可开关,未启用时跳过发送
|
||||
- 图形验证码(captcha)
|
||||
- 生成滑块拼图验证码,主图与滑块图以Base64形式返回,目标坐标保存在Redis,验证时比较偏移容差
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["开始"]) --> GenCode["生成6位数字验证码"]
|
||||
GenCode --> StoreRedis["存储到Redis<br/>键: verification:code:{type}:{email}<br/>过期: 10分钟"]
|
||||
StoreRedis --> RateLimit["设置发送频率限制<br/>键: verification:rate_limit:{type}:{email}<br/>过期: 1分钟"]
|
||||
RateLimit --> SendMail["发送邮件(根据类型选择模板)"]
|
||||
SendMail --> MailOK{"邮件发送成功?"}
|
||||
MailOK --> |是| Done(["结束"])
|
||||
MailOK --> |否| Clean["删除Redis验证码键"] --> Fail(["失败"])
|
||||
subgraph "图形验证码"
|
||||
GStart["生成滑块拼图验证码"] --> SaveCaptcha["保存目标坐标到Redis<br/>键: captcha:{id}<br/>过期: 5分钟"]
|
||||
SaveCaptcha --> ReturnBase64["返回主图/滑块图Base64与captchaId"]
|
||||
Verify["前端提交dx与captchaId"] --> LoadCaptcha["从Redis读取目标坐标"]
|
||||
LoadCaptcha --> Compare["比较dx与目标坐标容差"]
|
||||
Compare --> |通过| DelCaptcha["删除Redis记录"]
|
||||
Compare --> |失败| Warn["返回失败"]
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L26-L119)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [captcha_service.go](file://internal/service/captcha_service.go#L75-L166)
|
||||
- [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77)
|
||||
|
||||
章节来源
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L119)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [captcha_service.go](file://internal/service/captcha_service.go#L18-L166)
|
||||
- [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77)
|
||||
|
||||
### 请求/响应示例(示例路径)
|
||||
- 注册
|
||||
- 请求:POST /api/v1/auth/register
|
||||
- 示例路径:[注册请求体定义](file://internal/types/common.go#L33-L40)
|
||||
- 响应:包含token与用户信息
|
||||
- 登录
|
||||
- 请求:POST /api/v1/auth/login
|
||||
- 示例路径:[登录请求体定义](file://internal/types/common.go#L27-L31)
|
||||
- 响应:包含token与用户信息
|
||||
- 发送验证码
|
||||
- 请求:POST /api/v1/auth/send-code
|
||||
- 示例路径:[发送验证码请求体定义](file://internal/types/common.go#L49-L54)
|
||||
- 响应:通用成功响应
|
||||
- 重置密码
|
||||
- 请求:POST /api/v1/auth/reset-password
|
||||
- 示例路径:[重置密码请求体定义](file://internal/types/common.go#L55-L61)
|
||||
- 响应:通用成功响应
|
||||
|
||||
章节来源
|
||||
- [common.go](file://internal/types/common.go#L27-L61)
|
||||
|
||||
## 依赖关系分析
|
||||
- 组件耦合
|
||||
- 处理器依赖服务层;服务层依赖JWT与密码工具、Redis与邮件服务
|
||||
- 中间件依赖JWT服务,统一拦截受保护资源
|
||||
- 外部依赖
|
||||
- Redis:验证码存储与限流
|
||||
- SMTP:邮件发送
|
||||
- JWT:令牌签发与校验
|
||||
- 循环依赖
|
||||
- 未见循环依赖迹象
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
AH["auth_handler.go"] --> US["user_service.go"]
|
||||
AH --> VS["verification_service.go"]
|
||||
CH["captcha_handler.go"] --> CS["captcha_service.go"]
|
||||
US --> JWT["jwt.go"]
|
||||
US --> PW["password.go"]
|
||||
VS --> EM["email.go"]
|
||||
VS --> CFG["config.go"]
|
||||
CS --> CFG
|
||||
M["auth.go"] --> JWT
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [auth_handler.go](file://internal/handler/auth_handler.go#L17-L249)
|
||||
- [user_service.go](file://internal/service/user_service.go#L12-L122)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L14-L119)
|
||||
- [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77)
|
||||
- [captcha_service.go](file://internal/service/captcha_service.go#L18-L166)
|
||||
- [auth.go](file://internal/middleware/auth.go#L12-L56)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L10-L71)
|
||||
- [password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [email.go](file://pkg/email/email.go#L15-L163)
|
||||
- [config.go](file://pkg/config/config.go#L67-L107)
|
||||
|
||||
## 性能考量
|
||||
- Redis命中率
|
||||
- 验证码键短生命周期,建议合理设置Redis内存与淘汰策略,避免热键阻塞
|
||||
- 邮件发送
|
||||
- 异步化与重试策略可进一步优化(当前实现为同步发送),避免阻塞请求线程
|
||||
- JWT负载
|
||||
- Claims中仅包含必要字段,减少token体积,提升网络传输效率
|
||||
- 登录日志
|
||||
- 失败日志写入数据库可能带来IO压力,建议结合异步队列或批量写入
|
||||
|
||||
## 故障排查指南
|
||||
- 登录失败
|
||||
- 现象:401未授权
|
||||
- 排查:确认用户名/邮箱是否存在、密码是否正确、账号状态是否正常
|
||||
- 参考路径:[登录失败处理](file://internal/service/user_service.go#L84-L104)
|
||||
- 验证码错误/过期
|
||||
- 现象:400错误
|
||||
- 排查:确认验证码类型与邮箱匹配、是否在有效期内、是否被重复使用
|
||||
- 参考路径:[验证码校验](file://internal/service/verification_service.go#L79-L98)
|
||||
- 邮件发送失败
|
||||
- 现象:发送验证码接口报错
|
||||
- 排查:检查邮件服务开关、SMTP配置、网络连通性
|
||||
- 参考路径:[邮件发送](file://pkg/email/email.go#L29-L105)
|
||||
- JWT无效
|
||||
- 现象:访问受保护资源401
|
||||
- 排查:确认Authorization头格式、token是否过期、签名是否正确
|
||||
- 参考路径:[JWT校验](file://pkg/auth/jwt.go#L55-L71)
|
||||
|
||||
章节来源
|
||||
- [user_service.go](file://internal/service/user_service.go#L84-L104)
|
||||
- [verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [email.go](file://pkg/email/email.go#L29-L105)
|
||||
- [jwt.go](file://pkg/auth/jwt.go#L55-L71)
|
||||
|
||||
## 结论
|
||||
该认证API围绕“路由-处理器-服务-基础设施”清晰分层,实现了完整的注册、登录、验证码与重置密码流程。JWT用于无状态鉴权,bcrypt保障密码安全,Redis与SMTP分别承担验证码与邮件能力。通过严格的参数校验、限流与一次性验证码使用策略,有效提升了安全性与可用性。建议后续引入图形验证码与更完善的限流策略,进一步增强抗暴力破解能力。
|
||||
|
||||
## 附录
|
||||
- 安全最佳实践
|
||||
- 密码加密:始终使用bcrypt
|
||||
- JWT过期:合理设置过期时间,短期会话建议缩短
|
||||
- 验证码:短有效期、一次性使用、限流
|
||||
- 传输安全:生产环境强制HTTPS
|
||||
- 日志脱敏:避免泄露敏感信息
|
||||
- 环境变量与配置
|
||||
- JWT密钥与过期小时数、邮件SMTP配置、Redis连接参数等均通过环境变量注入
|
||||
|
||||
章节来源
|
||||
- [config.go](file://pkg/config/config.go#L67-L107)
|
||||
343
.qoder/repowiki/zh/content/API参考/认证API/重置密码.md
Normal file
343
.qoder/repowiki/zh/content/API参考/认证API/重置密码.md
Normal file
@@ -0,0 +1,343 @@
|
||||
# 重置密码
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go)
|
||||
- [internal/handler/routes.go](file://internal/handler/routes.go)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go)
|
||||
- [internal/types/common.go](file://internal/types/common.go)
|
||||
- [internal/model/response.go](file://internal/model/response.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向开发者与测试人员,系统化梳理“重置密码”API的完整实现与使用规范,覆盖以下要点:
|
||||
- 接口定位与HTTP方法:POST /api/v1/auth/reset-password
|
||||
- 请求体字段与校验规则:email、verificationCode、newPassword
|
||||
- 响应格式与错误码:统一的业务状态码与错误消息
|
||||
- 流程说明:验证码验证 → 密码加密更新 → 成功响应
|
||||
- 安全考虑:验证码一次性使用、有效期控制、密码复杂度要求
|
||||
|
||||
## 项目结构
|
||||
围绕“重置密码”的关键文件分布如下:
|
||||
- 路由注册:在路由组中将 /api/v1/auth/reset-password 绑定到处理器
|
||||
- 处理器:接收请求、绑定参数、调用服务层、返回统一响应
|
||||
- 服务层:
|
||||
- 验证码服务:生成、发送、验证、删除;验证码一次性使用与有效期控制
|
||||
- 用户服务:根据邮箱查找用户并更新密码(密码经加密后持久化)
|
||||
- 工具与模型:
|
||||
- 密码工具:bcrypt 加密与校验
|
||||
- 请求类型:ResetPasswordRequest 的字段与约束
|
||||
- 响应模型:统一响应结构与常用状态码
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "接口层"
|
||||
R["路由注册<br/>/api/v1/auth/reset-password"]
|
||||
H["处理器<br/>ResetPassword"]
|
||||
end
|
||||
subgraph "服务层"
|
||||
VS["验证码服务<br/>VerifyCode/Generate/Send/Delete"]
|
||||
US["用户服务<br/>ResetUserPassword"]
|
||||
end
|
||||
subgraph "工具与模型"
|
||||
PW["密码工具<br/>bcrypt 加密/校验"]
|
||||
RT["请求类型<br/>ResetPasswordRequest"]
|
||||
RM["响应模型<br/>统一响应/状态码"]
|
||||
end
|
||||
R --> H
|
||||
H --> VS
|
||||
H --> US
|
||||
US --> PW
|
||||
H --> RM
|
||||
VS --> RM
|
||||
RT --> H
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L40-L98)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [internal/types/common.go](file://internal/types/common.go#L55-L61)
|
||||
- [internal/model/response.go](file://internal/model/response.go#L1-L86)
|
||||
|
||||
章节来源
|
||||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
|
||||
## 核心组件
|
||||
- 接口路径与方法
|
||||
- 方法:POST
|
||||
- 路径:/api/v1/auth/reset-password
|
||||
- 请求体结构
|
||||
- 字段:
|
||||
- email:字符串,必填,需符合邮箱格式
|
||||
- verificationCode:字符串,必填,长度必须为6
|
||||
- newPassword:字符串,必填,长度范围为6~128
|
||||
- 校验来源:请求类型定义与处理器绑定校验
|
||||
- 响应格式
|
||||
- 成功:统一响应结构,code=200,message=“操作成功”,data为空或简要提示
|
||||
- 失败:统一错误响应结构,包含业务状态码与错误消息
|
||||
- 错误码
|
||||
- 400:请求参数错误(如字段缺失、格式不符、长度不符)
|
||||
- 400:验证码错误或已过期
|
||||
- 500:服务端内部错误(如数据库异常)
|
||||
|
||||
章节来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
- [internal/types/common.go](file://internal/types/common.go#L55-L61)
|
||||
- [internal/model/response.go](file://internal/model/response.go#L27-L52)
|
||||
|
||||
## 架构总览
|
||||
下图展示“重置密码”端到端调用链路与各模块职责。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant G as "Gin路由"
|
||||
participant H as "处理器 ResetPassword"
|
||||
participant VS as "验证码服务 VerifyCode"
|
||||
participant US as "用户服务 ResetUserPassword"
|
||||
participant PW as "密码工具 bcrypt"
|
||||
participant DB as "数据库"
|
||||
C->>G : "POST /api/v1/auth/reset-password"
|
||||
G->>H : "路由转发"
|
||||
H->>H : "绑定并校验请求体"
|
||||
H->>VS : "VerifyCode(email, code, type=reset_password)"
|
||||
VS-->>H : "验证通过/失败"
|
||||
alt "验证码失败"
|
||||
H-->>C : "400 错误响应"
|
||||
else "验证码通过"
|
||||
H->>US : "ResetUserPassword(email, newPassword)"
|
||||
US->>PW : "HashPassword(newPassword)"
|
||||
PW-->>US : "hashedPassword"
|
||||
US->>DB : "UpdateUserFields(password=hashed)"
|
||||
DB-->>US : "OK"
|
||||
US-->>H : "OK"
|
||||
H-->>C : "200 成功响应"
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 处理器:ResetPassword
|
||||
- 职责
|
||||
- 绑定并校验请求体
|
||||
- 调用验证码服务验证验证码(一次性使用)
|
||||
- 调用用户服务更新密码(密码加密存储)
|
||||
- 返回统一响应
|
||||
- 关键行为
|
||||
- 参数绑定失败:返回400
|
||||
- 验证码失败:返回400
|
||||
- 更新密码失败:返回500
|
||||
- 成功:返回200
|
||||
|
||||
章节来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
|
||||
### 验证码服务:VerifyCode 与发送流程
|
||||
- 验证码类型
|
||||
- reset_password:用于重置密码场景
|
||||
- 一次性使用
|
||||
- 验证通过后立即删除Redis中的验证码键值
|
||||
- 有效期控制
|
||||
- 默认10分钟
|
||||
- 发送频率限制
|
||||
- 同一邮箱同类型验证码在1分钟内不可重复发送
|
||||
- 发送流程
|
||||
- 生成6位数字验证码
|
||||
- 写入Redis(带过期时间)
|
||||
- 设置发送频率限制键
|
||||
- 发送邮件(按类型区分模板)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["开始"]) --> Bind["绑定请求体"]
|
||||
Bind --> Verify["VerifyCode(email, code, type)"]
|
||||
Verify --> Check{"验证码正确且未过期?"}
|
||||
Check --> |否| Err["返回400 错误"]
|
||||
Check --> |是| Delete["删除Redis中的验证码键"]
|
||||
Delete --> Next["进入下一步"]
|
||||
Err --> End(["结束"])
|
||||
Next --> End
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L218-L230)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
|
||||
章节来源
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L14-L24)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L40-L98)
|
||||
|
||||
### 用户服务:ResetUserPassword
|
||||
- 流程
|
||||
- 根据邮箱查询用户
|
||||
- 对新密码进行bcrypt加密
|
||||
- 更新用户记录的password字段
|
||||
- 错误处理
|
||||
- 用户不存在:返回错误
|
||||
- 加密失败:返回错误
|
||||
- 数据库更新失败:返回错误
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S(["开始"]) --> Find["根据邮箱查找用户"]
|
||||
Find --> Found{"找到用户?"}
|
||||
Found --> |否| E1["返回错误:用户不存在"]
|
||||
Found --> |是| Hash["HashPassword(newPassword)"]
|
||||
Hash --> HOK{"加密成功?"}
|
||||
HOK --> |否| E2["返回错误:密码加密失败"]
|
||||
HOK --> |是| Update["UpdateUserFields(password=hashed)"]
|
||||
Update --> UOK{"更新成功?"}
|
||||
UOK --> |否| E3["返回错误:数据库更新失败"]
|
||||
UOK --> |是| OK["返回成功"]
|
||||
E1 --> End(["结束"])
|
||||
E2 --> End
|
||||
E3 --> End
|
||||
OK --> End
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
|
||||
章节来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
|
||||
### 请求体与响应模型
|
||||
- 请求体字段与约束
|
||||
- email:必填,邮箱格式
|
||||
- verificationCode:必填,长度6
|
||||
- newPassword:必填,长度6~128
|
||||
- 响应模型
|
||||
- 成功:code=200,message=“操作成功”
|
||||
- 失败:code=400或500,message=错误描述
|
||||
|
||||
章节来源
|
||||
- [internal/types/common.go](file://internal/types/common.go#L55-L61)
|
||||
- [internal/model/response.go](file://internal/model/response.go#L27-L52)
|
||||
|
||||
## 依赖关系分析
|
||||
- 路由到处理器
|
||||
- /api/v1/auth/reset-password → ResetPassword
|
||||
- 处理器到服务层
|
||||
- ResetPassword → VerifyCode(验证码验证)
|
||||
- ResetPassword → ResetUserPassword(密码更新)
|
||||
- 服务层到工具
|
||||
- ResetUserPassword → HashPassword(bcrypt加密)
|
||||
- 服务层到存储
|
||||
- ResetUserPassword → UpdateUserFields(持久化)
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Routes["路由"] --> Handler["处理器 ResetPassword"]
|
||||
Handler --> VS["验证码服务"]
|
||||
Handler --> US["用户服务"]
|
||||
US --> PW["密码工具 bcrypt"]
|
||||
US --> DB["数据库"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
|
||||
章节来源
|
||||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L26)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L194-L249)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L166-L184)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
|
||||
## 性能考量
|
||||
- 验证码存储与访问
|
||||
- Redis作为验证码缓存,具备高并发读写能力;建议合理设置过期时间与限流键,避免热点攻击
|
||||
- 密码加密成本
|
||||
- bcrypt默认成本较高,单次加密有一定CPU开销;建议在高并发场景下关注服务实例的CPU占用与延迟
|
||||
- 数据库更新
|
||||
- 单字段更新通常很快;建议确保数据库连接池配置合理,避免阻塞
|
||||
|
||||
## 故障排查指南
|
||||
- 常见错误与定位
|
||||
- 400 参数错误:检查请求体字段是否齐全、格式是否正确、长度是否满足约束
|
||||
- 400 验证码错误/过期:确认验证码是否正确、是否已被使用(一次性)、是否超过有效期
|
||||
- 500 服务器错误:检查用户是否存在、密码加密是否成功、数据库更新是否异常
|
||||
- 日志与追踪
|
||||
- 处理器对失败场景会输出警告/错误日志,便于定位问题
|
||||
- 验证码生命周期
|
||||
- 验证通过即删除,确保验证码只能使用一次
|
||||
- 过期时间为10分钟,超过后无法再使用
|
||||
|
||||
章节来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L218-L249)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L79-L98)
|
||||
|
||||
## 结论
|
||||
“重置密码”API以清晰的职责划分与严格的参数校验保障了安全性与可用性。验证码一次性使用与有效期控制有效降低了滥用风险;密码采用bcrypt加密存储,符合安全最佳实践。统一的响应模型与错误码体系提升了接口一致性与可观测性。
|
||||
|
||||
## 附录
|
||||
|
||||
### 请求与响应示例
|
||||
- 请求示例(JSON)
|
||||
- POST /api/v1/auth/reset-password
|
||||
- Body:
|
||||
- email:字符串,必填,邮箱格式
|
||||
- verificationCode:字符串,必填,长度6
|
||||
- newPassword:字符串,必填,长度6~128
|
||||
- 成功响应示例(JSON)
|
||||
- Status:200
|
||||
- Body:
|
||||
- code:200
|
||||
- message:“操作成功”
|
||||
- data:空对象或简要提示
|
||||
- 失败响应示例(JSON)
|
||||
- Status:400 或 500
|
||||
- Body:
|
||||
- code:400 或 500
|
||||
- message:错误描述
|
||||
- error:详细错误信息(开发环境)
|
||||
|
||||
章节来源
|
||||
- [internal/types/common.go](file://internal/types/common.go#L55-L61)
|
||||
- [internal/model/response.go](file://internal/model/response.go#L27-L52)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L218-L249)
|
||||
|
||||
### 安全考虑
|
||||
- 验证码一次性使用
|
||||
- 验证通过后立即删除Redis中的验证码键,防止复用
|
||||
- 验证码有效期控制
|
||||
- 默认10分钟,超时即失效
|
||||
- 发送频率限制
|
||||
- 同一邮箱同类型验证码在1分钟内不可重复发送
|
||||
- 密码复杂度要求
|
||||
- newPassword长度范围为6~128,建议结合业务策略进一步增强复杂度(例如包含大小写字母、数字与特殊字符),当前实现以长度约束为主
|
||||
|
||||
章节来源
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L14-L24)
|
||||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L40-L98)
|
||||
- [internal/types/common.go](file://internal/types/common.go#L55-L61)
|
||||
Reference in New Issue
Block a user