一、设计流程

  1. 在pom文件中引入DefaultKaptcha的依赖(Jar包)。
  2. 在CaptchaConfig类中配置验证码相关的参数。
  3. 利用DefaultKaptcha实现类生成验证码图片。
  4. 利用Redis数据库对验证码进行缓存。
  5. 利用ImageIO类将验证码图片以流形式写入到内存中。
  6. 前端页面利用Img标签的src属性,根据Base64编码格式数据获取验证码图片显示。
  7. 校验时,从Redis中取出验证码并删除,进行判断是否正确。

二、实现过程

1、在pom文件中引入DefaultKaptcha的依赖。

            <dependency>
                <groupId>com.github.penggle</groupId>
                <artifactId>kaptcha</artifactId>
                <version>2.3.2</version>
            </dependency>

 2、在CaptchaConfig类中配置验证码相关的参数(字符验证码)。

/**
 * 验证码配置参数
 *
 * @author LBF
 */
@Configuration
public class CaptchaConfig
{
    /**
     * 配置生成字符验证码的参数
     * @return
     */
    @Bean(name = "captchaBean")
    public DefaultKaptcha getKaptchaBean()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        // 初始化一个Propertis对象,设定验证码参数
        Properties properties = new Properties();
        // 设置验证码图片宽度,默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 设置验证码图片高度,默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        // 设置边框,默认有  yes/no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 设置验证码文本字符颜色,默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
        // 验证码文本字符长度,默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        // 验证码文本字体样式,默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        // 配置其参数
        Config config = new Config(properties);
        // 使验证码参数生效
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

 3、验证码操作处理类。

1、利用DefaultKaptcha实现类生成验证码图片。

2、利用Redis数据库对验证码进行缓存。

3、利用ImageIO类将验证码图片以流形式写入到内存中。

/**
 * 验证码操作处理类  (可生成数字/字母)
 *
 * @author LBF
 */
@RestController
public class CaptchaController
{
    // Producer接口(DefaultKaptcha为接口的实现类)
    @Resource(name = "captchaBean")
    private Producer captchaProducer;

    // Redis缓存对象
    @Autowired
    private RedisCache redisCache;

    /**
     * 生成验证码方法
     */
    @GetMapping("/test")
    public AjaxResult getCode() throws IOException
    {
        // 自己封装的一个数据结果返回体,默认成功,
        AjaxResult ajax = AjaxResult.success();

        // 生成UUID,拼接用以作验证码的唯一标识
        String uuid = IdUtils.simpleUUID();
        // 设置缓存在Redis中验证码的KEY值
        String verifyKey = "captcha_codes:" + uuid;

        // 保存生成的验证码
        String capStr = null;
        // 保存验证码正确结果(设置缓存在Redis中验证码的Value值)
        String code = null;
        BufferedImage image = null;

        // 生成字符串验证码
        // 生成验证码与正确结果一致
        capStr = code = captchaProducer.createText();
        // 生成图片
        image = captchaProducer.createImage(capStr);

        // 向Redis中缓存基本对象,为了以后进行校验验证码(验证码KEY、正确结果code、验证码过期时间、时间颗粒度(以某计量为单位))
        redisCache.setCacheObject(verifyKey, code, 2, TimeUnit.MINUTES);
        // 图片信息转换成二进制流信息输出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try
        {
            // 通过ImageIO将图片以jpg格式,以流形式写入内存中
            ImageIO.write(image, "jpg", os);
        }
        catch (IOException e)
        {
            // 异常返回 
            return AjaxResult.error(e.getMessage());
        }

        ajax.put("uuid", uuid);
        // 利用Base64工具类,转换成字符数组输出给前端
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
}

 4、前端页面利用Img标签的src属性,根据Base64编码格式数据获取验证码图片显示。

    // 获取验证码方法
    getCode() {
      getCodeImg().then(res => {
          this.codeUrl = "data:image/gif;base64," + res.img;
          this.loginForm.uuid = res.uuid;
      });
    },
    <!-- 利用img标签,src属性根据Base64编码格式数据来获取验证码图。 -->
    <div class="login-code">
        <img :src="codeUrl" @click="getCode" class="login-code-img"/>
    </div>

 5、校验输入验证码。

    /**
     * 校验验证码
     * 
     * @param code 此处code为用户输入的验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public void validateCaptcha(String code, String uuid)
    {
        // 验证码的KEY值
        String verifyKey = "captcha_codes:" + uuid;
        // 从Redis中,根据KEY值获取Value值(正确验证码),即获取生成验证码时向Redis中缓存的数据
        String captcha = redisCache.getCacheObject(verifyKey);
        // 删除Redis中的KEY值
        redisCache.deleteObject(verifyKey);
        if (captcha == null)
        {
            // 若Redis中没有KEY对应的Value值,则可说明验证码过期被删除
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            // 调用equalsIgnoreCase方法,进行字符判断是否相等
            throw new CaptchaException();
        }
    }

三、测试结果(测试字符验证码校验结果)

以消息提示窗口作为测试观察------------->>>验证码正确情况

 

 以消息提示窗口作为测试观察------------->>>验证码错误情况

 

四、总结 

     本文介绍采用DefaultKaptcha类生成验证码,使用Redis数据库作为缓存,最终取出并进行验证。在设计过程中,仍然存在许多未能充分理解的位置,若在使用过程中出现问题或有更好的实现思路,可分享/指出,共同学习进步。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐