SpringBoot 验证码


前言

  • 框架:Spring Boot 2.3.12.RELEASE
  • 环境:JDK 1.8 + MySQL 8.0.19 + Redis 6.2.6

一、依赖导入

使用第三方依赖 kaptcha

<dependency>
    <groupId>pro.fessional</groupId>
    <artifactId>kaptcha</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>servlet-api</artifactId>
            <groupId>javax.servlet</groupId>
        </exclusion>
    </exclusions>
    <version>2.3.3</version>
</dependency>

值得注意的是,kaptcha 中内置了 Servlet 依赖
在这里插入图片描述
而 Spring Boot 内置了 Tomcat,避免发生依赖冲突,将 kaptcha 中的 Servlet 依赖使用 < exclusion > 标签排除

二、验证码文本生成器

顾名思义,用于生成验证码的一个工具类

kaptcha 提供了一个默认的验证码文本生成器 DefaultTextCreator,通过 getText() 方法来生成验证码
在这里插入图片描述

自定义

自定义验证码生成器,需要继承默认的验证码生成器 DefaultTextCreator

以数字运算验证码为例

  • 定义一个字符串数组,元素是进行运算的数字
  • 重写 getText() 方法

大致思路

  • 定义变量:运算结果 result、运算拼接 suC、两个随机数变量 x、y∈[0, 10]
  • 因为运算有四种,再定义一个随机数 [0,3] 变量 randomoperands 来判断进行哪种运算
  • 将随机数作为数组下标,获取运算的两个数字
  • 进行运算,将运算结果赋给 result
  • 利用运算拼接变量 suC 凭借当前运算式子,凭借成 运算数字 运算符 运算数字 =?@ 运算结果
  • 验证码生成
public class KaptchaTextCreator extends DefaultTextCreator {
    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");

    @Override
    public String getText() {
        Integer result = 0;
        Random random = new Random();
        int x = random.nextInt(10);
        int y = random.nextInt(10);
        StringBuilder suChinese = new StringBuilder();
        int randomoperands = random.nextInt(3);
        if (randomoperands == 0) {
            result = x * y;
            suChinese.append(CNUMBERS[x]);
            suChinese.append("*");
            suChinese.append(CNUMBERS[y]);
        }
        else if (randomoperands == 1) {
            if ((x != 0) && y % x == 0) {
                result = y / x;
                suChinese.append(CNUMBERS[y]);
                suChinese.append("/");
                suChinese.append(CNUMBERS[x]);
            }
            else {
                result = x + y;
                suChinese.append(CNUMBERS[x]);
                suChinese.append("+");
                suChinese.append(CNUMBERS[y]);
            }
        }
        else {
            if (x >= y) {
                result = x - y;
                suChinese.append(CNUMBERS[x]);
                suChinese.append("-");
                suChinese.append(CNUMBERS[y]);
            } else {
                result = y - x;
                suChinese.append(CNUMBERS[y]);
                suChinese.append("-");
                suChinese.append(CNUMBERS[x]);
            }
        }
        suChinese.append("=?@" + result);
        return suChinese.toString();
    }
}

三、配置

对于验证码,有随机字符串形式的验证码,也有数学运算的验证码等多种实现方式

验证码的样式需要使用 kaptcha 提供的 DefaultKaptcha 进行相关配置,可以通过配置类的方式,使用 @Bean 注解将其注入到容器中去

@SpringBootConfiguration
public class CaptchaConfig {
	@Bean(name = "captchaProducerMath")
    public DefaultKaptcha getKaptchaBeanMath() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty(KAPTCHA_BORDER, "yes");
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.zh.system.util.KaptchaTextCreator");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

样式是通过 DefaultKaptchasetConfig() 方法进配置的,其所需要的是 kaptcha 提供的 Config 对象作为参数。

而 Config 对象需要一个 Properties 对象来进行验证码样式的设置,Properties 可以看成是 key-value 都是 String 类型的 Map 集合

也就是说,决定验证码样式的是一组组 String 类型的 key-value,其中的 key 是由 kaptcha 提供的接口Constants 中的常量 ,value的设置也需要与常量向对应

四、实现

将验证码响应给前端

  • 通过 captchaProducerMath 将验证码以自定义的样式生成,此时返回的是字符串类型
  • 由上面可以,通过验证码生成器生成的验证码格式是:数字 运算符 数字 = ?@ 结果,所以对即进行拆分(split(“@”)),最终变成一个字符串数组,元素分别是数字 运算符 数字 = ?结果
  • 将字符串数组第一个元素作为参数传入 captchaProducerMath.createImage()方法,生成验证码图片
  • 将结果保存在 redis 中,验证时与 redis 中的值比较
  • 通过 FastByteArrayOutputStream 以及 JDK 提供的 ImageIO 类的 write() 将图片变为字节数组
  • 再将字节数组进行 Base64 编码的处理,同时需要注意,如果生成的编码超过 76 个字符时,会出现回车换行符(\r\n),需要利用 replaceAll() 进行替换处理
  • 将 Base64 编码响应给前端,前端 img 可以直接使用

代码

 @Autowired
 @Qualifier("captchaProducerMath")
 private Producer captchaProducerMath;
 @Autowired
 private RedisCache redisCache;

 @GetMapping("/captchaImage")
 public AjaxResult captchaImage(){
     AjaxResult ajaxResult = AjaxResult.success();
     String text = captchaProducerMath.createText();
     String[] split = text.split("@");
     String imgStr = split[0];
     String code = split[1];
     // 根据验证码,生成图片
     BufferedImage  image = captchaProducerMath.createImage(imgStr);
     // 将验证码保存到 redis 缓存中
     redisCache.setCacheObject(CacheConstants.CAPTCHA_CODE_KEY + uuid, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
     // 将图片转为字节数组,
     FastByteArrayOutputStream stream = new FastByteArrayOutputStream();
     try {
         ImageIO.write(image, "jpeg", stream);
     } catch (IOException e) {
         e.printStackTrace();
     }
     // 通过 Base64 将字节数组进行编码
     String imgBase64 = "data:image/jpeg;base64," + Base64.encode(stream.toByteArray());
     // 使用 Bash64 时,如果超过 76 个字符时,会出现回车换行符:\r\n,所以需要去掉
     imgBase64 = imgBase64.replaceAll("[\r\n]", "");
     ajaxResult.put("img", imgBase64);
     return ajaxResult;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值