解决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);
}
相关推荐
EatFan1 分钟前
一个二维码背后的系统设计:批次生成、绑定、扫码与数据统计怎么做?
java·后端·微信小程序·二维码·qrcode
石小石Orz6 分钟前
民间AI排行榜单新鲜出炉,Fable 5.1仅排第三
前端·后端·ai编程
小灰灰搞电子20 分钟前
Rust Once 、OnceLock、LazyLock 一次性初始化详解
开发语言·后端·rust
我不会起名字32233 分钟前
一天一道算法题(35):电话号码的字母组合
java·数据结构·后端·python·leetcode·go·回溯
星栈1 小时前
ADK-Rust 是什么?Rust 生态新一代 AI Agent 开发套件
后端·agent
盖伦发发1 小时前
业务开发常用设计模式:状态、策略、工厂、适配器、模板方法
后端·软件工程
程序员老赵2 小时前
Docker 部署 XXL-JOB:轻松搭建分布式任务调度平台
后端·docker·开源
用户233376852182 小时前
Docker镜像找不到排障实录-CRLF跨平台暗雷
后端
程序员cxuan2 小时前
从 0 到 1 速通 WorkBuddy
人工智能·后端·程序员
薛定谔的算法2 小时前
M01:环境搭建与第一个 Java 程序
后端