13 KiB
13 KiB
重置密码
**本文引用的文件** - [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)目录
简介
本文件面向开发者与测试人员,系统化梳理“重置密码”API的完整实现与使用规范,覆盖以下要点:
- 接口定位与HTTP方法:POST /api/v1/auth/reset-password
- 请求体字段与校验规则:email、verificationCode、newPassword
- 响应格式与错误码:统一的业务状态码与错误消息
- 流程说明:验证码验证 → 密码加密更新 → 成功响应
- 安全考虑:验证码一次性使用、有效期控制、密码复杂度要求
项目结构
围绕“重置密码”的关键文件分布如下:
- 路由注册:在路由组中将 /api/v1/auth/reset-password 绑定到处理器
- 处理器:接收请求、绑定参数、调用服务层、返回统一响应
- 服务层:
- 验证码服务:生成、发送、验证、删除;验证码一次性使用与有效期控制
- 用户服务:根据邮箱查找用户并更新密码(密码经加密后持久化)
- 工具与模型:
- 密码工具:bcrypt 加密与校验
- 请求类型:ResetPasswordRequest 的字段与约束
- 响应模型:统一响应结构与常用状态码
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
- internal/handler/auth_handler.go
- internal/service/verification_service.go
- internal/service/user_service.go
- pkg/auth/password.go
- internal/types/common.go
- internal/model/response.go
章节来源
核心组件
- 接口路径与方法
- 方法:POST
- 路径:/api/v1/auth/reset-password
- 请求体结构
- 字段:
- email:字符串,必填,需符合邮箱格式
- verificationCode:字符串,必填,长度必须为6
- newPassword:字符串,必填,长度范围为6~128
- 校验来源:请求类型定义与处理器绑定校验
- 字段:
- 响应格式
- 成功:统一响应结构,code=200,message=“操作成功”,data为空或简要提示
- 失败:统一错误响应结构,包含业务状态码与错误消息
- 错误码
- 400:请求参数错误(如字段缺失、格式不符、长度不符)
- 400:验证码错误或已过期
- 500:服务端内部错误(如数据库异常)
章节来源
架构总览
下图展示“重置密码”端到端调用链路与各模块职责。
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
- internal/service/verification_service.go
- internal/service/user_service.go
- pkg/auth/password.go
详细组件分析
处理器:ResetPassword
- 职责
- 绑定并校验请求体
- 调用验证码服务验证验证码(一次性使用)
- 调用用户服务更新密码(密码加密存储)
- 返回统一响应
- 关键行为
- 参数绑定失败:返回400
- 验证码失败:返回400
- 更新密码失败:返回500
- 成功:返回200
章节来源
验证码服务:VerifyCode 与发送流程
- 验证码类型
- reset_password:用于重置密码场景
- 一次性使用
- 验证通过后立即删除Redis中的验证码键值
- 有效期控制
- 默认10分钟
- 发送频率限制
- 同一邮箱同类型验证码在1分钟内不可重复发送
- 发送流程
- 生成6位数字验证码
- 写入Redis(带过期时间)
- 设置发送频率限制键
- 发送邮件(按类型区分模板)
flowchart TD
Start(["开始"]) --> Bind["绑定请求体"]
Bind --> Verify["VerifyCode(email, code, type)"]
Verify --> Check{"验证码正确且未过期?"}
Check --> |否| Err["返回400 错误"]
Check --> |是| Delete["删除Redis中的验证码键"]
Delete --> Next["进入下一步"]
Err --> End(["结束"])
Next --> End
图表来源
章节来源
用户服务:ResetUserPassword
- 流程
- 根据邮箱查询用户
- 对新密码进行bcrypt加密
- 更新用户记录的password字段
- 错误处理
- 用户不存在:返回错误
- 加密失败:返回错误
- 数据库更新失败:返回错误
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
图表来源
章节来源
请求体与响应模型
- 请求体字段与约束
- email:必填,邮箱格式
- verificationCode:必填,长度6
- newPassword:必填,长度6~128
- 响应模型
- 成功:code=200,message=“操作成功”
- 失败:code=400或500,message=错误描述
章节来源
依赖关系分析
- 路由到处理器
- /api/v1/auth/reset-password → ResetPassword
- 处理器到服务层
- ResetPassword → VerifyCode(验证码验证)
- ResetPassword → ResetUserPassword(密码更新)
- 服务层到工具
- ResetUserPassword → HashPassword(bcrypt加密)
- 服务层到存储
- ResetUserPassword → UpdateUserFields(持久化)
graph LR
Routes["路由"] --> Handler["处理器 ResetPassword"]
Handler --> VS["验证码服务"]
Handler --> US["用户服务"]
US --> PW["密码工具 bcrypt"]
US --> DB["数据库"]
图表来源
- internal/handler/routes.go
- internal/handler/auth_handler.go
- internal/service/verification_service.go
- internal/service/user_service.go
- pkg/auth/password.go
章节来源
- internal/handler/routes.go
- internal/handler/auth_handler.go
- internal/service/verification_service.go
- internal/service/user_service.go
- pkg/auth/password.go
性能考量
- 验证码存储与访问
- Redis作为验证码缓存,具备高并发读写能力;建议合理设置过期时间与限流键,避免热点攻击
- 密码加密成本
- bcrypt默认成本较高,单次加密有一定CPU开销;建议在高并发场景下关注服务实例的CPU占用与延迟
- 数据库更新
- 单字段更新通常很快;建议确保数据库连接池配置合理,避免阻塞
故障排查指南
- 常见错误与定位
- 400 参数错误:检查请求体字段是否齐全、格式是否正确、长度是否满足约束
- 400 验证码错误/过期:确认验证码是否正确、是否已被使用(一次性)、是否超过有效期
- 500 服务器错误:检查用户是否存在、密码加密是否成功、数据库更新是否异常
- 日志与追踪
- 处理器对失败场景会输出警告/错误日志,便于定位问题
- 验证码生命周期
- 验证通过即删除,确保验证码只能使用一次
- 过期时间为10分钟,超过后无法再使用
章节来源
结论
“重置密码”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:详细错误信息(开发环境)
章节来源
安全考虑
- 验证码一次性使用
- 验证通过后立即删除Redis中的验证码键,防止复用
- 验证码有效期控制
- 默认10分钟,超时即失效
- 发送频率限制
- 同一邮箱同类型验证码在1分钟内不可重复发送
- 密码复杂度要求
- newPassword长度范围为6~128,建议结合业务策略进一步增强复杂度(例如包含大小写字母、数字与特殊字符),当前实现以长度约束为主
章节来源