5.3 验证码机制
概述
图形验证码由 utility/captcha 生成:6 位字符(排除易混淆字符)、PNG 渲染(TTF 字体 + 干扰线/噪点)、Redis 缓存 300 秒、一次性校验。字体缺失自动降级 SVG 渲染。
生成流程(GET /api/captcha)
text
1) 生成随机码:captcha.length 位(默认 6,范围 4~8),
字符集 captcha.chars(默认排除 0O、1lI 等易混淆字符)
2) 生成 uuid 作为缓存键
3) 缓存:easygoadmin:captcha:{uuid} = 验证码值,TTL captcha.expire(300s)
4) 渲染 PNG:TTF 字体(resource/static/fonts/Vera.ttf)+ 干扰线(默认 8 条)
+ 噪点(默认 500 个);字体缺失降级 SVG
5) 返回 {"key": uuid, "captcha": "data:image/png;base64,..."}(前端直接展示)校验流程(captcha.Verify)
text
Verify(ctx, key, code):
1) GET easygoadmin:captcha:{uuid}(命中即删除——一次性校验)
2) 未命中 → 校验失败(过期或已用过)
3) 命中 → 与提交值比对(大小写不敏感处理)
4) 配置 captcha.bypassCode 且提交值相等 → 免校验直接通过
(仅开发调试使用,生产环境必须留空)配置项(manifest/config/config.yaml)
yaml
captcha:
expire: 300 # 有效期(秒)
bypassCode: "618618" # 万能验证码:携带该值免校验,仅开发调试使用,生产留空
length: 6 # 字符数,取值范围 4 到 8
chars: "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" # 字符集,已排除易混淆字符
fontPath: "resource/static/fonts/Vera.ttf" # TTF 字体路径,缺失降级 SVG
imageWidth: 160 # 图片宽度(字符放不下时自动加宽防裁剪)
imageHeight: 50 # 图片高度
fontSize: 40 # 字体大小
noiseLines: 8 # 干扰线数量(越多越难识别)
noiseDots: 500 # 噪点数量使用场景
| 场景 | 行为 |
|---|---|
| 登录 | 提供 key 时强制校验(auth Login 第 1 步) |
| 令牌兑换 | 认证入口,与登录同享 authLimit 严阈值 |
| 开发调试 | code 填 bypassCode(默认 618618)免校验 |
| 生产 | bypassCode 必须留空(发布检查清单项) |
安全要点
- 一次性:命中即删,防重放(同一验证码不能二次使用)
- 短 TTL:300 秒过期,防拖库后长期有效
- 独立限流:/api/captcha 属认证入口,受 authLimit=10/分钟/IP 约束(防刷图)
- 缓存层:经 utility/cache(Redis 优先、内存降级)——内存降级时验证码单实例内有效
常见问题
| 症状 | 原因与处理 |
|---|---|
| 验证码图片不显示 | 后端未启动 / /api/captcha 被限流;字体缺失不影响(降级 SVG) |
| 填对了也报验证码错误 | 已用过(一次性)或超 300s;重新获取 |
| 前端一直验证码错误但后端日志正常 | 检查 key 是否与图片配套(每次生成 key 不同) |
| 生产环境想跳过验证码 | 禁止配置 bypassCode;调试可在测试环境进行 |