Java案例怎么验证验证码有效性?

wen java案例 16

本文目录导读:

Java案例怎么验证验证码有效性?

  1. 基础逻辑:验证码验证的本质
  2. 案例一:使用 Kaptcha(传统 Session 方案)
  3. 案例二:使用 EasyCaptcha(支持 Redis + 分布式)
  4. 关键验证规则(必须注意)
  5. 完整校验流程图

在Java中验证验证码有效性,通常有两种场景:前后端分离(后端生成+校验)和传统单体应用(Session存储),下面给出3种主流验证码库的实现案例。


基础逻辑:验证码验证的本质

无论用哪种库,核心步骤都是:

  1. 生成阶段:生成验证码文本 → 存入服务端(Session/Redis) → 返回图片给前端
  2. 验证阶段:用户提交文本 → 从服务端取出正确文本 → 比对(通常忽略大小写)→ 清除/标记已使用

案例一:使用 Kaptcha(传统 Session 方案)

适用于:单体应用、不涉及分布式 Session 的项目。

1 依赖(Maven)

<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

2 生成验证码 Controller

@GetMapping("/captcha")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 1. 设置响应类型
    response.setDateHeader("Expires", 0);
    response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
    response.addHeader("Cache-Control", "post-check=0, pre-check=0");
    response.setHeader("Pragma", "no-cache");
    response.setContentType("image/jpeg");
    // 2. 生成验证码文本(Kaptcha默认使用DefaultKaptcha)
    String capText = captchaProducer.createText();
    // 3. 存入 Session(key 自定义,如 "captchaCode")
    request.getSession().setAttribute("captchaCode", capText);
    // 4. 生成图片并写入响应流
    BufferedImage bi = captchaProducer.createImage(capText);
    ServletOutputStream out = response.getOutputStream();
    ImageIO.write(bi, "jpg", out);
    out.flush();
    out.close();
}

3 验证验证码有效性 Controller

@PostMapping("/login")
public String login(@RequestParam String username,
                    @RequestParam String password,
                    @RequestParam String captchaInput,
                    HttpServletRequest request) {
    // 1. 从 Session 获取正确验证码
    String correct = (String) request.getSession().getAttribute("captchaCode");
    // 2. 清除验证码(防止重复使用)
    request.getSession().removeAttribute("captchaCode");
    // 3. 有效性校验
    if (correct == null || !correct.equalsIgnoreCase(captchaInput)) { // 忽略大小写
        return "验证码错误或已过期";
    }
    // 4. 验证通过,继续业务逻辑
    return "登录成功";
}

案例二:使用 EasyCaptcha(支持 Redis + 分布式)

适用于:前后端分离、分布式部署。

1 依赖

<dependency>
    <groupId>com.github.whvcse</groupId>
    <artifactId>easy-captcha</artifactId>
    <version>1.6.2</version>
</dependency>

2 生成验证码(UUID + Redis 存储)

@GetMapping("/captcha")
public Result<Map<String, String>> getCaptcha() {
    // 1. 生成验证码对象(数字+字母,4位)
    SpecCaptcha captcha = new SpecCaptcha(130, 48, 4);
    // 2. 获取文本(如 "A3bC")
    String code = captcha.text().toLowerCase(); // 统一转小写存储
    // 3. 生成唯一标识符(作为Redis的key)
    String uuid = UUID.randomUUID().toString().replace("-", "");
    // 4. 存入 Redis(过期时间 5 分钟)
    redisTemplate.opsForValue().set(RedisKeys.CAPTCHA_KEY + uuid, code, 5, TimeUnit.MINUTES);
    // 5. 返回给前端:uuid(作为凭证) + 图片base64
    Map<String, String> map = new HashMap<>();
    map.put("captchaKey", uuid);
    map.put("captchaImg", captcha.toBase64());  // 前端直接<img src="data:image/...">显示
    return Result.success(map);
}

3 验证验证码有效性 Controller

@PostMapping("/login")
public Result<?> login(@RequestBody LoginForm form) {
    // 1. 从请求中拿到 captchaKey 和前端输入的 captchaInput
    String captchaKey = form.getCaptchaKey();
    String captchaInput = form.getCaptchaInput();
    // 2. 从 Redis 取出正确的验证码
    String correctCode = redisTemplate.opsForValue().get(RedisKeys.CAPTCHA_KEY + captchaKey);
    // 3. **立即删除**(防止多次使用)
    redisTemplate.delete(RedisKeys.CAPTCHA_KEY + captchaKey);
    // 4. 有效性校验
    if (correctCode == null) {
        return Result.error("验证码已过期,请重新获取");
    }
    if (!correctCode.equalsIgnoreCase(captchaInput)) {
        return Result.error("验证码错误");
    }
    // 5. 验证通过,继续业务
    return Result.success("登录成功");
}

关键验证规则(必须注意)

1 大小写不敏感

推荐统一转为小写后再比较:

correctCode.equalsIgnoreCase(inputCode);
// 或者
correctCode.toLowerCase().equals(inputCode.toLowerCase());

2 一次性使用

  • 无论是 Session 还是 Redis,验证成功后必须立即删除
  • 防止同一个验证码被重复提交。

3 过期机制

  • Session:默认 30 分钟失效,建议手动设置更短(如 5 分钟)。
  • Redis:设置过期时间 5, TimeUnit.MINUTES

4 防暴力破解

  • 同一 IP 短时间内验证失败次数过多 → 临时锁定(可加计数器到 Redis)。
  • 验证码本身可以加 干扰线、扭曲、噪点(EasyCaptcha / Kaptcha 配置)。

完整校验流程图

前端                    后端                Redis / Session
 ─────────              ──────────          ────────────
 请求获取验证码  ──→ 生成code + 存储Code  ──→ 保存code
                   ↓
 返回{img, key}  ←── code不返回给前端
                   ↓
 用户填写验证码 + key
                   ↓
 提交表单       ──→  取出code(根据key)
                   ↓
 比较code       ←── 忽略大小写比对比
                   ↓
 删除key对应的code   ──→ 清除
                   ↓
 返回成功/失败

场景 推荐技术 存储方案 验证核心
单体应用 Kaptcha Session session.getAttribute
分布式 / 前后端分离 EasyCaptcha + Redis Redis + UUID redis.get(key) + 删除
高安全需求 算术验证码 / 滑动验证 均可 同上 + 轨迹校验

验证码有效验证的黄金三原则:

  1. 存储 ≠ 返回(code不进返回体)
  2. 验证即删(一次有效)
  3. 忽略大小写

抱歉,评论功能暂时关闭!