343 lines
13 KiB
Markdown
343 lines
13 KiB
Markdown
|
|
# 重置密码
|
|||
|
|
|
|||
|
|
<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)
|