Spring Boot 实现验证码:Hutool-captcha、AJ-Captcha、EasyCaptcha 到底怎么选?

验证码是每个 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 兼容性的问题吗?评论区聊聊。

相关推荐
seconp1 小时前
基于Spring Boot和Vue 3的智慧旅游网站:住宿预订、行程规划与千问接入
vue.js·spring boot·毕业设计·软件工程·课程设计·旅游·毕设
vx_bisheyuange1 小时前
基于SpringBoot的校园数字化图书馆系统
spring boot·毕业设计
马优晨1 小时前
Java中的dto是什么
java·开发语言·java中的dto是什么·java的dto是什么·dto在java中是什么
小蒜学长1 小时前
基于Springboot+Vue的高校教师教学业绩综合管理系统的设计与开发(代码+数据库+LW)
java·数据库·spring boot·后端·教学业绩管理·三级权限
熊哈哈O_o1 小时前
千亿级时序数据:存储压缩、高速写入与时序超表技术
后端
Mikko71 小时前
Spring Boot 3.5.16 自带的 Tomcat 10.1.55 中了哪些 CVE?其中一条是修上一个漏洞时带进来的
java·spring boot·后端·安全·tomcat
十年Java程序媛1 小时前
Java 内部类全解|成员 / 静态 / 匿名内部类,理清和 Lambda 的区别
java·spring boot·面试
站大爷IP1 小时前
Python的字符串查找把我坑惨了,原来find和index的区别这么大
后端
sp421 小时前
一个支持 Java 8 的 MCP SDK(支持最新 2026-07-28 协议)
后端·mcp