解决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);
}
相关推荐
北漂老男孩5 分钟前
Spring 框架核心机制深度解析【AI模型互搏生成】
java·后端·spring
c无序36 分钟前
【Go-2】基本语法与数据类型
开发语言·后端·golang
攒了一袋星辰2 小时前
Spring是如何实现scope作用域支持
java·后端·spring
小黑屋说YYDS2 小时前
Spring Validation校验
java·后端·spring
接着奏乐接着舞2 小时前
spring boot 注解 @bean
spring boot·后端·python
fashia3 小时前
Java转Go日记(四十四):Sql构建
开发语言·后端·golang·go
程序员Bears4 小时前
Flask项目实践:构建功能完善的博客系统(含评论与标签功能)
后端·python·flask
弥鸿4 小时前
RestFul操作ElasticSearch:索引与文档全攻略
后端·elasticsearch·restful
blues_C4 小时前
二、【环境搭建篇】:Django 和 Vue3 开发环境准备
后端·python·django·vue3·测试平台
Murphy_lx5 小时前
django回忆录(Python的一些基本概念, pycharm和Anaconda的配置, 以及配合MySQL实现基础功能, 适合初学者了解)
后端·python·pycharm·django