解决hutool图形验证码bug

从网上下载了一个开源的项目,发现登录界面的验证码无论怎么刷新,显示的都是同一个,即使换一个浏览器也是相同的图形验证码,说一下解决bug的过程

😶修改前的源代码如下(部分代码)

java 复制代码
import cn.hutool.captcha.*;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final AbstractCaptcha abstractCaptcha;
  
    @Override
    public CaptchaResult getCaptcha() {
        //获取验证码文本,例如 1+4=
        String captchaCode = abstractCaptcha.getCode();
        String imageBase64Data = abstractCaptcha.getImageBase64Data();
        
        String captchaKey = IdUtil.fastSimpleUUID();
        // 验证码文本缓存至Redis,用于登录校验
        redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey, captchaCode,captchaProperties.getExpireSeconds(), TimeUnit.SECONDS);
        //......
    }
}

😐分析上面的代码,首先作者使用了Lombok提供的@RequiredArgsConstructor注解,它的作用是为下面被 final 修饰的变量生成构造方法,即利用构造方法将AbstractCaptcha对象注入到Spring容器中,但是通过这种方式注入,默认情况下Bean是单例的,即多次请求会复用同一个Bean 。

😐其次,阅读hutool有关abstractCaptcha.getCode()部分的代码,如下,可以看到,在第一次生成code时,就将生成的code赋值给了成员变量 code,再结合前面的单例模式,真相大白。

java 复制代码
//验证码
protected String code;

@Override
public String getCode() {
   if (null == this.code) {
      createCode();
   }
   return this.code;
}

@Override
public void createCode() {
   generateCode();

   final ByteArrayOutputStream out = new ByteArrayOutputStream();
   ImgUtil.writePng(createImage(this.code), out);
   this.imageBytes = out.toByteArray();
}

//生成验证码字符串
protected void generateCode() {
   this.code = generator.generate();
}

😎最终修改业务代码如下

java 复制代码
import cn.hutool.captcha.*;
import cn.hutool.captcha.generator.MathGenerator;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    //private final AbstractCaptcha abstractCaptcha; 
  
    @Override
    public CaptchaResult getCaptcha() {
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 45, 4, 4);
        // 自定义验证码内容为四则运算方式
        captcha.setGenerator(new MathGenerator(1));
        String captchaCode = captcha.getCode();
        String captchaBase64 = captcha.getImageBase64Data();
        
        String captchaKey = IdUtil.fastSimpleUUID();
        // 验证码文本缓存至Redis,用于登录校验
        redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey, captchaCode,captchaProperties.getExpireSeconds(), TimeUnit.SECONDS);
        //......
    }
}

😴阅读hutool关于createShearCaptcha()方法的源码,每次调用都会new一个新对象

java 复制代码
/**
 * 创建扭曲干扰的验证码,默认5位验证码
 *
 * @param width     图片宽
 * @param height    图片高
 * @param codeCount 字符个数
 * @param thickness 干扰线宽度
 * @return {@link ShearCaptcha}
 * @since 3.3.0
 */
public static ShearCaptcha createShearCaptcha(int width, int height, int codeCount, int thickness) {
   return new ShearCaptcha(width, height, codeCount, thickness);
}
相关推荐
稻草猫.3 分钟前
MyBatis进阶:动态SQL与MyBatis Generator插件使用
java·数据库·后端·spring·mvc·mybatis
qq_256247059 分钟前
Docker 部署 OpenClaw 踩坑实录:Web UI 访问、飞书配对及自定义模型配置
后端
困惑阿三11 分钟前
全栈部署排雷手册:从 405 报错到飞书推送成功
服务器·前端·后端·nginx·阿里云·node.js·飞书
bug攻城狮14 分钟前
为什么 Spring Boot 要单元测试?
spring boot·后端·单元测试
iPadiPhone15 分钟前
性能之基:Java IO 体系深度解析、面试陷阱与实战指南
java·开发语言·后端·面试
野犬寒鸦16 分钟前
从零起步学习JVM|| 第二章:JVM基本组成及JVM内存区域详解
服务器·开发语言·后端·学习·面试·职场和发展
iPadiPhone18 分钟前
Java NIO 核心原理解析、性能调优与大厂面试精要
java·后端·面试·nio
无名-CODING24 分钟前
从零开始!Vue3+SpringBoot前后端分离项目Docker部署实战(中):Spring Boot后端与Docker Compose串联
spring boot·后端·docker
Victor3563 小时前
MongoDB(52)如何配置分片?
后端
Victor3563 小时前
MongoDB(53)什么是分片键?
后端