2.1 KiB
2.1 KiB
5.3 验证码机制
:::tip 概述
图形验证码由 utility/captcha 生成 SVG/PNG dataURL,答案存缓存(TTL 300 秒)且一码一用。登录接口携带 key 时强制校验,配合认证接口限流防爆破。
:::
生命周期
GET /api/captcha(公开接口)
→ captcha.Generate:随机字符(captcha.length)+ 随机 key
→ 答案存 cache(CacheKeyCaptcha(key),TTL=captcha.expire)
→ 返回 { key, captcha: dataURL }(CaptchaRes)
POST /api/login 携带 key + code
→ captcha.Verify:比对答案 → 无论成败删除缓存键(一码一用,防重放)
→ 登录继续
配置(config.yaml captcha 节)
| 键 | 默认 | 说明 |
|---|---|---|
| expire | 300 | 有效期(秒) |
| length | 6 | 字符数(4–8) |
| chars | ABCDEFGHJKLMNPQRSTUVWXYZ23456789 | 排除易混淆字符(0O、1lI) |
| fontPath | resource/fonts/Vera.ttf | TTF 字体;缺失降级 SVG 渲染 |
| imageWidth / imageHeight / fontSize | 160 / 50 / 40 | 尺寸(字符放不下自动加宽) |
| noiseLines / noiseDots | 8 / 500 | 干扰线 / 噪点 |
| bypassCode | 空 | 万能码:携带该值免校验,仅开发调试 |
:::warning 生产红线
app.prod=true 时非空 bypassCode 会被启动校验直接拒绝——万能码绝不能带上线。
:::
前端接入
登录页从 /api/captcha 拿 uuid 与图片,提交时回传两者。前端四种登录表单(账密/手机/扫码/注册)中需要验证码的均走同一契约。
渲染实现
优先 TTF 字体渲染 PNG(opentype + golang.org/x/image),字体文件缺失时降级为 SVG 文本渲染——两种格式前端同为 <img src=dataURL> 消费,无感知差异。
与其他防护的配合
| 防护 | 层 |
|---|---|
| 验证码 | 人机校验(一码一用) |
| authLimit 限流 | 10 次/分钟/IP(登录/验证码/令牌兑换共享配额) |
| 失败日志 | gin_login_log status=1 留痕 |
三层叠加使暴力破解在 IP 与验证两道关卡上都不可行。