验证码是每个 Web 系统的标配,但选型这件事,踩坑的人特别多。
最常见的翻车场景:项目用 Session 存验证码,本地开发一切正常,一上生产、一加负载均衡,验证码永远校验失败------因为第一次请求落在 A 节点,第二次校验请求落在 B 节点,Session 里根本没有那个验证码。另一个高频坑:项目升级到 Spring Boot 3,引入某个验证码库后直接启动报错,原因是库内部还在用 javax.servlet,而 Spring Boot 3 已经全面切换到 jakarta.servlet。
验证码看起来简单,但选型要考虑的东西不少:存储方式、并发场景、前端交互复杂度、Spring Boot 版本兼容性。
这篇文章不堆 API,只解决一个问题:你的场景,到底该选哪个?
先说结论:
- 传统图形验证码(4 位字符),快速集成 → Hutool-captcha
- 想要更好的用户体验和安全性,滑动/点选 → AJ-Captcha
- 需要 GIF、算术、中文等多种图形验证码样式 → EasyCaptcha
- Spring Boot 3 项目 + 行为验证码 → AJ-Captcha 需要额外适配,或考虑 Captcha Plus
- 分布式部署,验证码需要跨节点共享 → 任何方案都必须配 Redis,不能用 Session
一、先搞清楚:验证码方案的两条技术路线
当前 Java 生态的验证码方案,本质上分成两条路线。
路线一:图形验证码。 服务端生成一张带干扰线的图片,用户看图输入字符。这是最传统的方案,实现简单,但用户体验一般------看不清要刷新,看得清又可能被 OCR 破解。
路线二:行为验证码。 用户不需要输入字符,只需要完成一个动作------拖动滑块拼图,或者按顺序点击文字。服务端采集用户的行为轨迹来判断是不是真人。这是目前的主流趋势,用户体验好,防机器能力也更强。
选型的第一步不是比库,而是先明确:你的业务场景,需要图形验证码还是行为验证码?
一般来说:
- 后台管理系统、内部系统 → 图形验证码足够,Hutool 或 EasyCaptcha
- 面向 C 端的登录、注册、敏感操作 → 行为验证码更合适,AJ-Captcha
- 已有 Spring Security 的项目 → 需要额外考虑验证码接口的放行配置
二、Hutool-captcha:轻量图形验证码的首选
它是什么
Hutool 是一个 Java 工具类库,它的 cn.hutool.captcha 包提供了开箱即用的图形验证码生成能力。核心类是 CaptchaUtil,一行代码就能生成验证码图片。
Hutool 提供四种验证码类型:LineCaptcha (线段干扰)、CircleCaptcha (圆圈干扰)、ShearCaptcha (扭曲干扰,抗机器识别能力较强)、GifCaptcha(GIF 动态验证码)。
依赖与用法
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
生成验证码并存入 Redis:
@RestController
public class CaptchaController {
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/captcha")
public void getCaptcha(HttpServletResponse response) throws IOException {
// 生成验证码(宽 200,高 100,4 位字符)
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 150);
// 生成唯一 key
String captchaKey = UUID.randomUUID().toString();
// 将验证码文本存入 Redis,有效期 5 分钟
redisTemplate.opsForValue().set(
"captcha:" + captchaKey,
captcha.getCode(),
5, TimeUnit.MINUTES
);
// 将 key 放入响应头,前端提交时携带
response.setHeader("Captcha-Key", captchaKey);
response.setContentType("image/png");
captcha.write(response.getOutputStream());
}
}
校验逻辑:
@PostMapping("/login")
public Result login(@RequestBody LoginDTO dto) {
String redisKey = "captcha:" + dto.getCaptchaKey();
String storedCode = redisTemplate.opsForValue().get(redisKey);
if (storedCode == null) {
return Result.fail("验证码已过期");
}
if (!storedCode.equalsIgnoreCase(dto.getCaptchaCode())) {
return Result.fail("验证码错误");
}
// 校验通过后立即删除,防止重复使用
redisTemplate.delete(redisKey);
// ... 继续登录逻辑
}
适合谁
后台管理系统、内部系统、对用户体验要求不高的场景。Hutool 的优势是零学习成本,如果你已经在用 Hutool,验证码功能可以直接复用现有的依赖。
注意: 一定用 Redis 存验证码,不要用 Session。即使当前是单机部署,也建议预留 Redis,避免后续扩展时踩坑。
三、AJ-Captcha:行为验证码的成熟方案
它是什么
AJ-Captcha 是安居客开源的行为验证码组件,支持滑动拼图 和文字点选 两种交互方式,后端提供纯 Java 实现和 Spring Boot Starter,前端提供了 Vue、React、Android、iOS、Flutter 等多端示例。
它的核心逻辑和传统验证码不同:用户完成滑动或点选动作后,前端把行为数据(滑动轨迹、坐标偏移等)提交到后端,后端调用 captchaService.verification() 做二次校验,判断是不是真人操作。
依赖与配置
<dependency>
<groupId>com.anji-plus</groupId>
<artifactId>captcha-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
application.yml 配置:
aj:
captcha:
cache-type: redis # 分布式部署必须用 redis,单机可用 local
expires-in: 300 # 验证码有效期(秒)
aes-status: false # 测试环境关闭 AES 加密,生产可开启
控制器直接调用 AJ-Captcha 提供的 CaptchaService,不需要自己写校验逻辑:
@RestController
@RequestMapping("/captcha")
public class CaptchaController {
@Resource
private CaptchaService captchaService;
@RequestMapping("/get")
public ResponseModel get(@RequestParam(defaultValue = "blockPuzzle") String type) {
CaptchaVO vo = new CaptchaVO();
vo.setCaptchaType(type); // blockPuzzle=滑动拼图,clickWord=文字点选
return captchaService.get(vo);
}
@PostMapping("/check")
public ResponseModel check(@RequestBody CaptchaVO vo) {
return captchaService.check(vo);
}
}
前端引入 AJ-Captcha 的 JS SDK,调用 /captcha/get 渲染验证码组件,用户完成操作后把结果提交到 /captcha/check。AJ-Captcha 会自动处理验证码的生成、存储、校验全流程。
Spring Boot 3 的兼容性问题
这是一个必须提前知道的坑。AJ-Captcha 1.4.0 版本不支持 Spring Boot 3,内部依赖的是 Spring Boot 2.5.5 的类。如果你的项目是 Spring Boot 3,直接引入会启动失败。
解决方案有两个:
方案一:使用 AJ-Captcha 的纯 Jar 包模式,自行适配。 不引入 Starter,只引入 captcha-core,手动配置 CaptchaService 和缓存实现,绕过对 Spring Boot 2.x 自动配置的依赖。这需要一定的适配工作量。
方案二:改用 Captcha Plus。 Captcha Plus 是 AJ-Captcha 的衍生项目,明确提供了 Spring Boot 3 支持,Spring Boot 3 项目请使用 2.x 分支。
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>2.0.1</version>
</dependency>
适合谁
面向 C 端的登录、注册、敏感操作场景。滑动验证码的用户体验远好于传统字符验证码,防机器能力也更强。如果你的项目是 Spring Boot 2.x,AJ-Captcha 1.4.0 是最省心的选择。如果是 Spring Boot 3,优先考虑 Captcha Plus,或者做好自行适配的准备。
四、EasyCaptcha:图形验证码的"样式库"
它是什么
EasyCaptcha 是一个专门生成图形验证码的 Java 类库,特点是支持多种验证码样式:GIF 动画、中文验证码、算术验证码等。如果你觉得 Hutool 默认的线段干扰验证码样式太单调,想要更丰富的视觉效果,EasyCaptcha 是一个补充选择。
依赖与用法
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
// 生成算术验证码(如 "3 + 5 = ?")
ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48);
String code = captcha.text(); // 结果是 "8"
// 生成 GIF 验证码
GifCaptcha gifCaptcha = new GifCaptcha(130, 48);
// 输出到响应流
captcha.out(response.getOutputStream());
EasyCaptcha 和 Hutool 的定位高度重合,选哪个主要看你对验证码样式的需求。如果只需要基础的线段干扰验证码,Hutool 更轻量;如果需要 GIF、算术、中文等多种样式,EasyCaptcha 的样式库更丰富。
注意: EasyCaptcha 在 Spring Boot 3 下的兼容性需要验证。有第三方项目 EasyCaptchaBoot 声称支持 Spring Boot 3.x,但这不是官方维护的,使用前需要评估风险。
五、选型决策树
| 你的场景 | 首选方案 | 备选方案 | 注意事项 |
|---|---|---|---|
| 后台管理系统 + Spring Boot 2.x/3.x | Hutool-captcha | EasyCaptcha | 必须配 Redis 存验证码 |
| C 端登录 + Spring Boot 2.x | AJ-Captcha | --- | 用户体验最好 |
| C 端登录 + Spring Boot 3.x | Captcha Plus | AJ-Captcha 纯 Jar 模式 | AJ-Captcha 1.4.0 不兼容 SB3 |
| 需要 GIF/算术验证码 | EasyCaptcha | Hutool(仅基础样式) | Spring Boot 3 兼容性需验证 |
| 分布式部署 | 任何方案 + Redis | --- | 绝对不能用 Session |
| 已有 Spring Security | 需额外放行验证码接口 | --- | AJ-Captcha 需配置放行 /captcha/** |
六、避坑清单
存储相关:
- 绝对不要用 Session 存验证码。 单机开发没问题,一加负载均衡就必挂。验证码必须存在 Redis 或分布式缓存中,key 用 UUID,value 是验证码文本,并设置合理的过期时间。
- 校验通过后立即删除验证码。 防止同一个验证码被重复使用,尤其是登录场景。
Spring Boot 3 兼容性相关:
- AJ-Captcha 1.4.0 不兼容 Spring Boot 3,引入后启动会报 ClassNotFoundException 或
NoClassDefFoundError,根源是内部依赖 Spring Boot 2.5.5 和javax.servlet。Spring Boot 3 项目请使用 Captcha Plus 或自行适配。 - Hutool 5.8.x 对 Spring Boot 3 的兼容性较好,但需要注意 hutool-all 会引入全部模块,如果只想用验证码功能,可以只引入
hutool-captcha模块以减少依赖体积。
AJ-Captcha 配置相关:
- 分布式部署时
cache-type必须设为redis,不能用默认的local。local模式下验证码存在 JVM 内存中,多节点部署时会校验失败。 - 如果项目使用 Spring Security,需要在 Security 配置中放行
/captcha/**接口,否则前端请求验证码时会被拦截返回 401。
通用相关:
- 验证码接口要做好限流,防止被恶意刷取消耗服务端资源。AJ-Captcha 内置了接口限流配置,Hutool 方案需要自己实现。
- 验证码有效期不宜过长,建议 2--5 分钟。过长会增加被暴力破解的风险。
七、总结
Spring Boot 实现验证码,核心看三个维度:交互方式、Spring Boot 版本、部署架构。
如果你只需要一个快速可用的图形验证码,Hutool-captcha 是最省心的选择------一行代码生成,配合 Redis 存储,十分钟就能跑通。
如果你想给用户更好的体验,且项目是 Spring Boot 2.x ,AJ-Captcha 是最成熟的滑动验证码方案,前后端代码都齐全。
如果你的项目已经升级到 Spring Boot 3 ,AJ-Captcha 需要绕路,优先考虑 Captcha Plus,或者做好自行适配的心理准备。
如果你需要 GIF 或算术验证码这类特殊样式,EasyCaptcha 是一个补充选项。
最后一句忠告:无论选哪个方案,验证码的存储都不要用 Session。 Redis 是标配,哪怕当前是单机部署,也提前配好,否则扩展时一定翻车。
你正在用哪个方案做验证码?是 Hutool、AJ-Captcha,还是其他?遇到过 Session 丢失或者 Spring Boot 3 兼容性的问题吗?评论区聊聊。