460 lines
18 KiB
Markdown
460 lines
18 KiB
Markdown
# 认证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) |