解决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);
}
相关推荐
PetterHillWater7 分钟前
AI编程之CodeBuddy的小试
后端·aigc
codervibe25 分钟前
如何用 Spring Security 构建无状态权限控制系统(含角色菜单控制)
java·后端
codervibe29 分钟前
项目中如何用策略模式实现多角色登录解耦?(附实战代码)
java·后端
expect7g33 分钟前
Flink-Checkpoint-2.OperatorChain
后端·flink
大葱白菜34 分钟前
🧱 Java 抽象类详解:从基础到实战,掌握面向对象设计的核心基石
后端·程序员
SimonKing41 分钟前
颠覆传统IO:零拷贝技术如何重塑Java高性能编程?
java·后端·程序员
mCell1 小时前
为什么我们需要 `.proto` 文件
后端·微服务·架构
mit6.8242 小时前
[Meetily后端框架] AI摘要结构化 | `SummaryResponse`模型 | Pydantic库 | vs marshmallow库
c++·人工智能·后端
陈随易2 小时前
VSCode v1.102发布,AI体验大幅提升
前端·后端·程序员
生无谓2 小时前
什么是跨域,如何处理跨域
后端