重置验证码接口必须同步清理旧ID并返回新ID和图片,不能仅生成新验证码;需显式调用store.Delete(oldID),禁止暴露answer字段,且重置逻辑须为独立路由而非中间件。

重置验证码接口不能只调用 captcha.Generate() 后返回新 ID 和图片——必须同步清理旧 ID,否则会堆积无效记录、浪费内存,且可能被用于绕过校验逻辑。
重置时必须显式删除旧 captcha ID
很多人写重置接口时只生成新验证码,却忘了删旧的。base64Captcha 的 store(比如 DefaultMemStore)不会自动覆盖同名 key,旧 ID 仍可被反复校验,攻击者只要拿到旧 ID 就能重放请求。
- 调用
store.Delete(oldID)是必须步骤,不能省略 - 如果前端没传旧 ID(比如首次加载),跳过删除即可,不用报错
- 若用 Redis 存储,
Delete会发DEL命令;内存存储则直接从 map 删除 - 不要依赖
Verify(..., true)的自动清理——它只在校验成功时触发,而重置是无条件清理
重置接口需返回新 ID + 新图片,且不暴露答案
后端生成新验证码后,必须把新 id 和 b64s 一起返回,前端才能更新图片和绑定新 ID。但绝不能在响应里带 answer 字段,哪怕 debug 模式下也建议关掉日志输出。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
- 调试时可用
global.Log.Infof("[CAPTCHA_DEBUG] ID: %s, Code: %s", id, answer),但上线前必须注释或用if gin.Mode() == gin.DebugMode包裹 - 前端每次调用重置,都应丢弃当前输入框内容,避免用户误提交旧验证码
- 返回结构体字段名保持一致,比如统一用
idKey和image,别一会captcha_id一会captchaId
避免在 Gin 中间件里做重置逻辑
有人把重置封装成中间件,结果发现每次请求都触发生成,或者上下文丢失导致 ID 返回为空。根本原因是中间件执行时机早于路由匹配,且无法区分“生成”和“校验”两类请求。
立即学习“go语言免费学习笔记(深入)”;
- 重置必须是独立路由,例如
POST /api/v1/captcha/reset,由 handler 显式控制流程 - 不要在中间件里调用
captcha.Generate(),那属于业务逻辑,不是通用拦截行为 - 如果想复用驱动(
base64Captcha.DriverString),应在init()或服务启动时初始化一次,全局复用 - 字体文件(如
"wqy-microhei.ttc")加载开销大,重复 new driver 会导致 CPU 和内存抖动
最易忽略的一点:重置后若用户立刻提交表单,但前端没来得及更新隐藏域里的 captcha_id,就会拿旧 ID 去校验——这要求前端必须监听重置成功回调,并原子性地替换 ID 和清空输入框。后端没法替前端做这事,只能靠接口契约约束。

















