Java使用生成验证码的方案和代码

验证码的实现方式

kaptcha的实现方式

Constantdescriptiondefault
kaptcha.border图片边框,合法值:yes,noyes
kaptcha.border.color边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue.black
kaptcha.image.width图片宽200
kaptcha.image.height图片高50
kaptcha.producer.impl图片实现类com.google.code.kaptcha.impl.DefaultKaptcha
kaptcha.textproducer.impl文本实现类com.google.code.kaptcha.text.impl.DefaultTextCreator
kaptcha.textproducer.char.string文本集合,验证码值从此集合中获取abcde2345678gfynmnpwx
kaptcha.textproducer.char.length验证码长度5
kaptcha.textproducer.font.names字体Arial, Courier
kaptcha.textproducer.font.size字体大小40px.
kaptcha.textproducer.font.color字体颜色,合法值: r,g,b 或者 white,black,blue.black
kaptcha.textproducer.char.space文字间隔2
kaptcha.noise.impl干扰实现类com.google.code.kaptcha.impl.DefaultNoise
kaptcha.noise.color干扰 颜色,合法值: r,g,b 或者 white,black,blue.black
kaptcha.obscurificator.impl图片样式:
水纹 com.google.code.kaptcha.impl.WaterRipple
鱼眼 com.google.code.kaptcha.impl.FishEyeGimpy
阴影 com.google.code.kaptcha.impl.ShadowGimpycom.google.code.kaptcha.impl.WaterRipple
kaptcha.background.impl背景实现类com.google.code.kaptcha.impl.DefaultBackground
kaptcha.background.clear.from背景颜色渐变,开始颜色light grey
kaptcha.background.clear.to背景颜色渐变, 结束颜色white
kaptcha.word.impl文字渲染器com.google.code.kaptcha.text.impl.DefaultWordRenderer
kaptcha.session.keysession keyKAPTCHA_SESSION_KEY
kaptcha.session.datesession dateKAPTCHA_SESSION_DATE

1. pom文件中导入kaptcha依赖

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

2. 添加Kaptcha配置类

package com.example.demo;

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.Properties;

@Component
public class KaptchaConfig {

    /**
     * 验证码 生成的bean
     */
    /*@Bean
    public DefaultKaptcha captchaProducer() {
        DefaultKaptcha captchaProducer = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "100");
        properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "30");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "22");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "6");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "LIGHT_GRAY");
        properties.setProperty(Constants.KAPTCHA_BACKGROUND_CLR_FROM, "WHITE");
        properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789");
        properties.setProperty(Constants.KAPTCHA_SESSION_CONFIG_KEY, "checkCode");
        Config config = new Config(properties);
        captchaProducer.setConfig(config);
        return captchaProducer;
    }*/

    /**
     * Kaptcha图形验证码工具配置类
     * @author: Xiongch
     * @param:
     * @return: com.google.code.kaptcha.Producer
     * @date: 2022/9/9 15:47
     */
    @Bean
    public Producer kaptchaProducer() {
        // 实例一个DefaultKaptcha
        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", "125");
        // 高度
        properties.setProperty("kaptcha.image.height", "50");
        // 设置session.key
        properties.setProperty("kaptcha.session.key", "code");
        // 设置文本长度
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        // 设置字体
        properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
        // 将以上属性设置为实例一个DefaultKaptcha的属性
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        // 将defaultKaptcha返回
        return defaultKaptcha;
    }
}

3. 添加控制层代码

package com.example.demo;

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;

@Controller
public class CommonController {

    @Autowired
    private Producer captchaProducer;

    @RequestMapping("/getCode")
    public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setDateHeader("Expires", 0);
        // Set standard HTTP/1.1 no-cache headers.
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // Set standard HTTP/1.0 no-cache header.
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg");
        // create the text for the image
        String capText = captchaProducer.createText();
        System.out.println("******************验证码是: " + capText + "******************");
        // store the text in the session
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
        // create the image with the text
        BufferedImage bi = captchaProducer.createImage(capText);
        ServletOutputStream out = response.getOutputStream();
        // write the data out
        ImageIO.write(bi, "jpg", out);
        try {
            out.flush();
        } finally {
            out.close();
        }
        return null;
    }

    @PostMapping("/loginh")
    public String loginByKaptcha(@RequestParam("verifyCode") String verifyCode, HttpSession session) {
        String kaptchaCode = session.getAttribute("verifyCode") + "";
        if (verifyCode.equals(kaptchaCode)) {
            return "success";
        }

        return "false";
    }
}

4. 查看生成的验证码

在这里插入图片描述

Hutool的实现方式简介

Hutool是一个便捷而又全面的Java工具类库,通过封装静态方法,降低学习API的成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

Hutool中的工具方法来自每个用户的不断完善,它涵盖了Java底层代码中的每个方面,既是大型项目开发中解决小问题的利器,也是小型项目中的有利助手;

Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

一、效果展示

1.1 LineCaptcha 线段干扰

在这里插入图片描述

1.2 ShearCaptcha 扭曲干扰

在这里插入图片描述

1.3 CircleCaptcha 圆圈干扰

在这里插入图片描述

二、Hutool工具类实现验证码生成

2.1 引入依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.31</version>
</dependency>

2.2 核心代码

package com.example.demo;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.ShearCaptcha;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Date;

/**
 * CaptchaController 验证码
 * @author Administrator
 * @version 2024/08/19 14:33
**/
@RestController
@RequestMapping("/captcha")
public class CaptchaController {

    private static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
    @Autowired
    private CaptchaProperties captchaProp;

    /**
     * 写出到流
     * @param response
     * @param session
     */
    @RequestMapping("/get")
    public void getCaptcha(HttpServletResponse response, HttpSession session) {
        // 定义图形验证码的长、宽、验证码字符数、干扰元素个数
        LineCaptcha captcha3 = CaptchaUtil.createLineCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 扭曲干扰
        ShearCaptcha captcha2 = CaptchaUtil.createShearCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 圆圈干扰
        CircleCaptcha captcha1 = CaptchaUtil.createCircleCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        //细节问题,不影响程序
        //设置返回类型
        response.setContentType("image/jpeg");
        //静止缓存
        response.setHeader("Progma", "No-cache");
        try {
            //图形验证码写出,可以写出到文件,也可以写出到流
            captcha1.write(response.getOutputStream());
            //同时将验证码内容和当前时间戳存储到Session中
            //此处Session的键可以配置成常量
            session.setAttribute(captchaProp.getSession().getKey(), captcha1.getCode());
            session.setAttribute(captchaProp.getSession().getDate(), new Date());
            log.info(captcha1.getCode());
            //关流
            response.getOutputStream().close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 写出到文件
     *
     * @param response
     * @param session
     * @return
     */
    @RequestMapping("/getFile")
    public boolean getCaptchaFile(HttpServletResponse response, HttpSession session) {
        //定义图形验证码的长、宽、验证码字符数、干扰元素个数
        LineCaptcha captcha3 = CaptchaUtil.createLineCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 扭曲干扰
        ShearCaptcha captcha2 = CaptchaUtil.createShearCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 圆圈干扰
        CircleCaptcha captcha1 = CaptchaUtil.createCircleCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        //图形验证码写出,可以写出到文件,也可以写出到流
        captcha1.write("d:/shear.png");
        //验证图形验证码的有效性,返回boolean值
        return captcha1.verify(captcha1.getCode());
    }

    //验证码生效时间限制
    private static final long VALID_MILLIS_TIME = 60 * 1000;

    @RequestMapping("/check")
    public boolean checkCaptcha(String captcha, HttpSession session) {
        //保证传过来的参数是合法的
        if (StringUtils.hasLength(captcha)) {
            //根据配置的默认session信息获取key和date
            String key = (String) session.getAttribute(captchaProp.getSession().getKey());
            Date date = (Date) session.getAttribute(captchaProp.getSession().getDate());
            //1.验证码正确(不区分大小写) 2.验证码还未失效
            return key.equalsIgnoreCase(captcha)
                    && System.currentTimeMillis() - date.getTime() < VALID_MILLIS_TIME;
        }
        return false;
    }
}

  1. 利用@Autowired注解注入一个CaptchaProperties对象,这个对象将用来配置图形验证码的属性的。这是因为代码中一些属性可能会在别处使用,且它们都是固定的,例如图形验证码的长和宽,Session的字段名等。将这些属性封装在一个对象中,并通过读取配置文件的方式绑定属性值。

  2. 在@RequestMapping注解的getCaptcha方法中,使用Hutool包的CaptchaUtil.createLineCaptcha方法创建了一个图形验证码对象lineCaptcha,其大小由配置文件中的captchaProp.getWidth()和captchaProp.getHeight()决定。然后,将验证码内容和当前时间戳存储到HttpSession中,以便后续校验验证码的时候使用。最后,将图形验证码写出到HttpServletResponse的输出流中,以返回给前端页面显示。

  3. 在@RequestMapping注解的checkCaptcha方法中,首先判断传入的验证码参数是否合法。如果合法,则从HttpSession中获取存储的验证码内容和时间戳信息,并进行比较。如果验证码正确且未过期,则返回true,否则返回false。

2.3 CaptchaProperties类的实现和配置文件(.yml)信息如下:

package com.example.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * CaptchaProperties 验证码配置类
 * @author Administrator
 * @version 2024/08/19 14:33
**/
@Data
@Configuration
@ConfigurationProperties(prefix = "captcha")
public class CaptchaProperties {
    // 图片宽
    private Integer width;
    // 图片高
    private Integer height;
    // 字符个数
    private Integer codeCount;
    // 干扰圆圈条数
    private Integer circleCount;
    private Session session; //使用自定义的Session类

    @Data
    public static class Session {
        private String key;
        private String date;
    }
}

captcha:
  width: 200
  height: 60
  codeCount: 4
  circleCount: 100
  session:
    key: CAPTCHA_SESSION_KEY
    date: CAPTCHA_SESSION_DATE

调用接口,如下
在这里插入图片描述

2.4 自定义纯数字的验证码(随机4位数字,可重复)

/**
     * 写出到流,自定义纯数字的验证码
     * @param response
     * @param session
     */
    @RequestMapping("/getCodeGenerator")
    public void getCodeGenerator(HttpServletResponse response, HttpSession session) {
        // 自定义纯数字的验证码(随机4位数字,可重复)
        RandomGenerator randomGenerator = new RandomGenerator("0123456789", 4);
        // 自定义纯汉字的验证码(随机4位汉字,可重复)
        RandomGenerator randomGenerator = new RandomGenerator("大家好,因基础设施故障,导致网易云音乐各端无法正常使用,我们正在加紧修复,非常抱歉。感谢大家的等待", 4);
        // 定义图形验证码的长、宽、验证码字符数、干扰元素个数
        LineCaptcha captcha3 = CaptchaUtil.createLineCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 扭曲干扰
        ShearCaptcha captcha2 = CaptchaUtil.createShearCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 圆圈干扰
        CircleCaptcha captcha1 = CaptchaUtil.createCircleCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        //细节问题,不影响程序
        //设置返回类型
        response.setContentType("image/jpeg");
        //静止缓存
        response.setHeader("Progma", "No-cache");
        try {
            captcha1.setGenerator(randomGenerator);
            //图形验证码写出,可以写出到文件,也可以写出到流
            captcha1.write(response.getOutputStream());
            //同时将验证码内容和当前时间戳存储到Session中
            //此处Session的键可以配置成常量
            session.setAttribute(captchaProp.getSession().getKey(), captcha1.getCode());
            session.setAttribute(captchaProp.getSession().getDate(), new Date());
            log.info(captcha1.getCode());
            //关流
            response.getOutputStream().close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

2.5 自定义验证码内容为四则运算方式

/**
     * 写出到流,// 自定义验证码内容为四则运算方式
     * @param response
     * @param session
     */
    @RequestMapping("/getCodeGenerator")
    public void getCodeGenerator(HttpServletResponse response, HttpSession session) {
        // 定义图形验证码的长、宽、验证码字符数、干扰元素个数
        LineCaptcha captcha3 = CaptchaUtil.createLineCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 扭曲干扰
        ShearCaptcha captcha2 = CaptchaUtil.createShearCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        // 圆圈干扰
        CircleCaptcha captcha1 = CaptchaUtil.createCircleCaptcha(captchaProp.getWidth(), captchaProp.getHeight(), captchaProp.getCodeCount(), captchaProp.getCircleCount());
        //细节问题,不影响程序
        //设置返回类型
        response.setContentType("image/jpeg");
        //静止缓存
        response.setHeader("Progma", "No-cache");
        try {
            // 自定义验证码内容为四则运算方式new MathGenerator(1),1为运算位数
            captcha1.setGenerator(new MathGenerator(1));
            //图形验证码写出,可以写出到文件,也可以写出到流
            captcha1.write(response.getOutputStream());
            //同时将验证码内容和当前时间戳存储到Session中
            //此处Session的键可以配置成常量
            session.setAttribute(captchaProp.getSession().getKey(), captcha1.getCode());
            session.setAttribute(captchaProp.getSession().getDate(), new Date());
            log.info(captcha1.getCode());
            //关流
            response.getOutputStream().close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

验证方法

@RequestMapping("/check")
    public boolean checkCaptcha(String captcha, HttpSession session) {
        //保证传过来的参数是合法的
        if (StringUtils.hasLength(captcha)) {
            //根据配置的默认session信息获取key和date
            String key = (String) session.getAttribute(captchaProp.getSession().getKey());
            Date date = (Date) session.getAttribute(captchaProp.getSession().getDate());
            boolean verify = new MathGenerator().verify(key, captcha);
            //1.验证码正确(不区分大小写) 2.验证码还未失效
            return verify
                    && System.currentTimeMillis() - date.getTime() < VALID_MILLIS_TIME;
        }
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值