解决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 Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥5 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约5 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee5 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐5 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs5 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐5 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司5 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
码农阿豪5 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
追逐时光者5 小时前
一个基于 .NET 与 Avalonia 构建、面向 TrinityCore 的开源 WoW 数据库编辑器
后端·.net