从网上下载了一个开源的项目,发现登录界面的验证码无论怎么刷新,显示的都是同一个,即使换一个浏览器也是相同的图形验证码,说一下解决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);
}