# 验证码API **本文引用的文件** - [routes.go](file://internal/handler/routes.go) - [captcha_handler.go](file://internal/handler/captcha_handler.go) - [captcha_service.go](file://internal/service/captcha_service.go) - [redis.go](file://pkg/redis/redis.go) - [response.go](file://internal/model/response.go) - [auth_handler.go](file://internal/handler/auth_handler.go) - [captcha_handler_test.go](file://internal/handler/captcha_handler_test.go) - [captcha_service_test.go](file://internal/service/captcha_service_test.go) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件面向验证码服务API的使用者与维护者,围绕路由组“/api/v1/captcha”下的两个核心端点: - GET /generate:生成图形验证码(滑块拼图),返回主图、滑块图、验证码唯一标识及目标Y坐标等信息。 - POST /verify:验证用户提交的滑动偏移量,判断是否在容差范围内,并在验证通过后清理缓存。 文档将详细说明验证码的生成机制(基于滑块拼图算法)、有效期管理(Redis过期策略)、验证流程与状态处理,并给出请求/响应示例。同时,说明该服务如何与注册、登录、更换邮箱等功能集成以提升安全性。 ## 项目结构 验证码API位于路由组“/api/v1/captcha”,由处理器与服务层共同实现,底层依赖Redis进行验证码数据的临时存储与过期控制。 ```mermaid graph TB subgraph "路由层" R["routes.go
注册 /api/v1/captcha/* 路由"] end subgraph "处理器层" GH["captcha_handler.go
Generate/Verify"] end subgraph "服务层" CS["captcha_service.go
GenerateCaptchaData/VerifyCaptchaData"] end subgraph "基础设施" RC["redis.go
Client 封装"] end R --> GH GH --> CS CS --> RC ``` 图表来源 - [routes.go](file://internal/handler/routes.go#L80-L86) - [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77) - [captcha_service.go](file://internal/service/captcha_service.go#L1-L166) - [redis.go](file://pkg/redis/redis.go#L1-L175) 章节来源 - [routes.go](file://internal/handler/routes.go#L80-L86) ## 核心组件 - 路由注册:在路由组“/api/v1/captcha”下注册“/generate”和“/verify”两个端点。 - 处理器:负责参数绑定、调用服务层、组织响应。 - 服务层:负责验证码生成(滑块拼图)、目标坐标提取、Redis存储与过期设置、验证偏移量、容差判断、验证后清理。 - Redis客户端:提供Set/Get/Del等基础能力,封装错误处理。 章节来源 - [routes.go](file://internal/handler/routes.go#L80-L86) - [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77) - [captcha_service.go](file://internal/service/captcha_service.go#L1-L166) - [redis.go](file://pkg/redis/redis.go#L1-L175) ## 架构总览 验证码API采用“路由 -> 处理器 -> 服务 -> Redis”的分层设计。生成阶段将目标坐标与容差信息写入Redis并设置过期时间;验证阶段读取目标坐标,计算容差并判定有效性,通过后立即删除对应键,防止重复使用。 ```mermaid sequenceDiagram participant C as "客户端" participant G as "Generate 处理器" participant S as "验证码服务" participant R as "Redis 客户端" C->>G : GET /api/v1/captcha/generate G->>S : GenerateCaptchaData(ctx, redisClient) S->>S : 生成滑块拼图数据 S->>R : Set(key=captcha : id, value={tx,ty}, expire=5m) S-->>G : 返回 masterImage, tileImage, captchaId, y G-->>C : JSON {code,data{masterImage,tileImage,captchaId,y}} ``` 图表来源 - [captcha_handler.go](file://internal/handler/captcha_handler.go#L12-L34) - [captcha_service.go](file://internal/service/captcha_service.go#L76-L135) - [redis.go](file://pkg/redis/redis.go#L60-L83) 章节来源 - [captcha_handler.go](file://internal/handler/captcha_handler.go#L12-L34) - [captcha_service.go](file://internal/service/captcha_service.go#L76-L135) ## 详细组件分析 ### 路由与端点 - 路由组“/api/v1/captcha” - GET /generate:生成验证码数据(主图、滑块图、验证码ID、目标Y坐标)。 - POST /verify:验证用户提交的滑动偏移量。 章节来源 - [routes.go](file://internal/handler/routes.go#L80-L86) ### 生成验证码(GET /generate) - 输入:无显式请求体。 - 输出:包含以下字段的数据对象 - masterImage:主图(base64字符串) - tileImage:滑块图(base64字符串) - captchaId:验证码唯一标识(用于后续验证) - y:目标Y坐标(前端可据此定位滑块初始位置) - 内部流程要点 - 生成唯一ID作为验证码会话标识。 - 生成滑块拼图数据,提取目标X/Y坐标。 - 将目标坐标序列化后写入Redis,键名前缀为“captcha:”,过期时间为300秒(5分钟)。 - 返回主图、滑块图、captchaId与修正后的Y坐标给前端。 请求/响应示例(路径) - 请求:GET /api/v1/captcha/generate - 响应:JSON - code:200 - data.masterImage:主图(base64) - data.tileImage:滑块图(base64) - data.captchaId:验证码ID - data.y:目标Y坐标 章节来源 - [captcha_handler.go](file://internal/handler/captcha_handler.go#L12-L34) - [captcha_service.go](file://internal/service/captcha_service.go#L76-L135) ### 验证验证码(POST /verify) - 请求体字段 - captchaId:必填,验证码唯一标识 - dx:必填,用户滑动的X轴偏移量 - 验证逻辑 - 从Redis读取目标坐标(tx, ty)。 - 使用容差值(默认±3像素)判断 dx 是否在 [tx-3, tx+3] 范围内。 - 若通过:删除Redis中的验证码记录,返回成功;若失败:返回失败。 - 错误处理 - 参数缺失或格式错误:返回400。 - Redis查询失败或键不存在:返回500或提示“验证码已过期或无效”。 请求/响应示例(路径) - 请求:POST /api/v1/captcha/generate - JSON:{ "captchaId": "...", "dx": 123 } - 响应: - 成功:JSON { "code": 200, "msg": "验证成功" } - 失败:JSON { "code": 400, "msg": "验证失败,请重试" } 章节来源 - [captcha_handler.go](file://internal/handler/captcha_handler.go#L36-L76) - [captcha_service.go](file://internal/service/captcha_service.go#L137-L166) ### 验证流程与容差机制 ```mermaid flowchart TD Start(["开始"]) --> Read["读取Redis中的目标坐标(tx, ty)"] Read --> Found{"键是否存在?"} Found --> |否| Expired["返回错误:验证码已过期或无效"] Found --> |是| Calc["计算 |dx - tx|"] Calc --> Check{"是否 ≤ 容差(3)?"} Check --> |是| Delete["删除Redis键"] Delete --> Pass["返回验证成功"] Check --> |否| Fail["返回验证失败"] Expired --> End(["结束"]) Pass --> End Fail --> End ``` 图表来源 - [captcha_service.go](file://internal/service/captcha_service.go#L137-L166) 章节来源 - [captcha_service.go](file://internal/service/captcha_service.go#L137-L166) ### 与注册/登录/更换邮箱的安全集成 - 注册(/api/v1/auth/register) - 在注册流程中,前端需先获取图形验证码并完成验证,再提交邮箱验证码(通过 /api/v1/auth/send-code 发送)。 - 后端在注册接口处验证邮箱验证码的有效性,确保注册过程安全。 - 登录(/api/v1/auth/login) - 登录流程通常不强制要求图形验证码,但可在高风险场景(如异常IP、频繁尝试)引入图形验证码作为二次防护。 - 更换邮箱(/api/v1/user/change-email) - 更换邮箱时,建议增加图形验证码与邮箱验证码双重校验,降低账户被恶意修改的风险。 章节来源 - [auth_handler.go](file://internal/handler/auth_handler.go#L17-L84) - [auth_handler.go](file://internal/handler/auth_handler.go#L149-L192) ## 依赖关系分析 - 路由层依赖处理器层暴露的处理函数。 - 处理器层依赖服务层提供的生成与验证方法。 - 服务层依赖Redis客户端进行数据持久化与过期控制。 - 通用响应模型用于统一返回格式(尽管验证码端点未直接使用该模型,但整体风格一致)。 ```mermaid graph LR Routes["routes.go"] --> Handler["captcha_handler.go"] Handler --> Service["captcha_service.go"] Service --> Redis["redis.go"] Handler --> Model["response.go"] ``` 图表来源 - [routes.go](file://internal/handler/routes.go#L80-L86) - [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77) - [captcha_service.go](file://internal/service/captcha_service.go#L1-L166) - [redis.go](file://pkg/redis/redis.go#L1-L175) - [response.go](file://internal/model/response.go#L1-L86) 章节来源 - [routes.go](file://internal/handler/routes.go#L80-L86) - [captcha_handler.go](file://internal/handler/captcha_handler.go#L1-L77) - [captcha_service.go](file://internal/service/captcha_service.go#L1-L166) - [redis.go](file://pkg/redis/redis.go#L1-L175) - [response.go](file://internal/model/response.go#L1-L86) ## 性能考虑 - 生成阶段 - 滑块拼图生成与base64编码在单次请求中完成,建议在前端缓存主图/滑块图以减少重复生成开销。 - 验证阶段 - Redis读取与删除均为O(1),验证逻辑简单,延迟低。 - 过期策略 - 默认5分钟过期,避免长期占用内存;过期后自动失效,无需手动清理。 - 并发与重复使用 - 验证通过后立即删除Redis键,防止同一验证码被重复使用。 章节来源 - [captcha_service.go](file://internal/service/captcha_service.go#L123-L135) - [captcha_service.go](file://internal/service/captcha_service.go#L157-L166) ## 故障排查指南 - 生成失败 - 现象:返回500,消息包含“生成验证码失败”。 - 可能原因:滑块拼图生成异常、Redis写入失败。 - 排查步骤:检查Redis连接状态、确认滑块拼图资源可用。 - 验证失败 - 现象:返回500或400,消息提示“验证码已过期或无效”或“验证失败,请重试”。 - 可能原因:captchaId无效或已过期、dx不在容差范围内、Redis读取异常。 - 排查步骤:确认captchaId正确、dx传值合理、Redis键存在且未过期。 - 参数错误 - 现象:返回400,消息提示“参数错误”。 - 可能原因:缺少captchaId或dx、JSON格式不正确。 - 排查步骤:检查请求体字段与类型。 章节来源 - [captcha_handler.go](file://internal/handler/captcha_handler.go#L12-L34) - [captcha_handler.go](file://internal/handler/captcha_handler.go#L36-L76) - [captcha_service.go](file://internal/service/captcha_service.go#L137-L166) ## 结论 验证码API通过滑块拼图与Redis过期机制,提供了轻量级、易部署的人机验证方案。其与注册、登录、更换邮箱等关键流程结合,可显著提升账户安全。建议在高风险场景引入图形验证码作为附加防护,并优化前端缓存策略以提升用户体验。 ## 附录 ### 请求/响应示例(路径) - 获取验证码 - 请求:GET /api/v1/captcha/generate - 响应:JSON { "code": 200, "data": { "masterImage": "...", "tileImage": "...", "captchaId": "...", "y": 123 } } - 验证验证码 - 请求:POST /api/v1/captcha/verify - JSON:{ "captchaId": "...", "dx": 123 } - 响应: - 成功:JSON { "code": 200, "msg": "验证成功" } - 失败:JSON { "code": 400, "msg": "验证失败,请重试" } 章节来源 - [captcha_handler.go](file://internal/handler/captcha_handler.go#L12-L34) - [captcha_handler.go](file://internal/handler/captcha_handler.go#L36-L76) ### 单元测试要点(路径) - 验证码生成与过期时间 - 测试:TestGenerateCaptchaData_ExpireTime - 断言:过期时间为300秒(5分钟) - 验证码验证逻辑 - 测试:TestVerifyCaptchaData_Logic - 断言:在容差范围内(±3)返回成功,超出范围返回失败 - Redis键生成 - 测试:TestVerifyCaptchaData_RedisKey - 断言:键名为“captcha:{id}” - 处理器响应格式与错误处理 - 测试:TestCaptchaHandler_ResponseFormat、TestCaptchaHandler_ErrorHandling - 断言:成功/失败响应格式与HTTP状态码 章节来源 - [captcha_service_test.go](file://internal/service/captcha_service_test.go#L1-L175) - [captcha_handler_test.go](file://internal/handler/captcha_handler_test.go#L1-L134)