代码包含生成验证码,验证验证码,以及验证码的失效时间


标题

  • 代码包含生成验证码,验证验证码,以及验证码的失效时间
  • 生成验证码和验证验证码的Controller
  • 生成验证码工具类


生成验证码和验证验证码的Controller

package com.example.security.zmain.generateImg;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.Map;

/**
 * 验证码Controller
 */
@RestController
public class VerifyCodeMain {

    /**
     * 生成验证码
     * @param request
     * @param response
     */
    @RequestMapping("/getVerifyCode")
    public void getVerifyCode(HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> map = VerifyCodeUtil.getVerifyCode();
        HttpSession session = request.getSession();
        session.setAttribute(VerifyCodeUtil.SESSION_KEY, map.get(VerifyCodeUtil.SESSION_KEY));
        // 禁止图像缓存。
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        // 将图像输出到Servlet输出流中。
        try {
            ServletOutputStream sos = response.getOutputStream();
            ImageIO.write((RenderedImage) map.get(VerifyCodeUtil.BUFFIMG_KEY), "jpeg", sos);
            sos.close();
            //设置验证码过期时间
            VerifyCodeUtil.removeAttrbute(session);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 验证验证码
     */
    @RequestMapping("/getVerifyCodeContent")
    public boolean getVerifyCodeContent(String inputVerifyCode){
        //获取当前线程绑定的request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();

        // 这个VerifyCodeFactory.SESSION_KEY是在servlet中存入session的名字
        String verifyCode = (String)session.getAttribute(VerifyCodeUtil.SESSION_KEY);
        if(null == verifyCode || verifyCode.isEmpty()){
            System.out.println("验证码过期请重新验证");
//            throw new DisabledException("验证码过期,请重新验证");
        }
        // 不分区大小写
        verifyCode = verifyCode.toLowerCase();
        inputVerifyCode = inputVerifyCode.toLowerCase();

//        log.info("验证码:{}, 用户输入:{}", verifyCode, inputVerifyCode);
        System.out.println(verifyCode+":"+inputVerifyCode);
        return verifyCode.equals(inputVerifyCode);
    }
}

生成验证码工具类

import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;

/**
 * 生成验证码的工具
 */
public class VerifyCodeUtil {

    /**
     * 照片存在session的key
     */
    public static final String SESSION_KEY = "verifyCode";

    public static final String BUFFIMG_KEY = "buffImg";
    /**
     * 验证码图片的宽度。
     */
    private static int width = 100;
    /**
     * 过期时长 一分钟
     */
    public static final long VERIFYCODE_TIMEOUT = 60*1000;
    /**
     *  验证码图片的高度。
     */
    private static int height = 30;
    /**
     * 验证码字符个数
     */
    private static int codeCount = 4;
    /**
     * 字体高度
     */
    private static int fontHeight;
    /**
     * 干扰线数量
     */
    private static int interLine = 12;
    /**
     * 第一个字符的x轴值,因为后面的字符坐标依次递增,所以它们的x轴值是codeX的倍数
     */
    private static int codeX;
    /**
     * codeY ,验证字符的y轴值,因为并行所以值一样
     */
    private static int codeY;
    /**
     * codeSequence 表示字符允许出现的序列值
     */
    static char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
            'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
            'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
    public static Map<String, Object> getVerifyCode(){
        Map<String, Object> result = new HashMap<>();
        //width-4 除去左右多余的位置,使验证码更加集中显示,减得越多越集中。
        //codeCount+1     //等比分配显示的宽度,包括左右两边的空格
        codeX = (width-4) / (codeCount+1);
        //height - 10 集中显示验证码
        fontHeight = height - 10;
        codeY = height - 7;
        // 定义图像buffer
        BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D gd = buffImg.createGraphics();
        // 创建一个随机数生成器类
        Random random = new Random();
        // 将图像填充为白色
        gd.setColor(Color.WHITE);
        gd.fillRect(0, 0, width, height);
        // 创建字体,字体的大小应该根据图片的高度来定。
        Font font = new Font("Times New Roman", Font.PLAIN, fontHeight);
        // 设置字体。
        gd.setFont(font);
        // 画边框。
        gd.setColor(Color.BLACK);
        gd.drawRect(0, 0, width - 1, height - 1);
        // 随机产生16条干扰线,使图象中的认证码不易被其它程序探测到。
        gd.setColor(Color.gray);
        for (int i = 0; i < interLine; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            gd.drawLine(x, y, x + xl, y + yl);
        }
        // randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
        StringBuffer randomCode = new StringBuffer();
        int red = 0, green = 0, blue = 0;
        // 随机产生codeCount数字的验证码。
        for (int i = 0; i < codeCount; i++) {
            // 得到随机产生的验证码数字。
            String strRand = String.valueOf(codeSequence[random.nextInt(36)]);
            // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            // 用随机产生的颜色将验证码绘制到图像中。
            gd.setColor(new Color(red,green,blue));
            gd.drawString(strRand, (i + 1) * codeX, codeY);
            // 将产生的四个随机数组合在一起。
            randomCode.append(strRand);
        }
        result.put(BUFFIMG_KEY, buffImg);
        result.put(SESSION_KEY, randomCode.toString());
        return result;
    }
    /**
     * 定时删除session中存在的验证码信息
     * @param session
     */
    public static void removeAttrbute(final HttpSession session) {
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                session.removeAttribute(SESSION_KEY);
                timer.cancel();
            }
        }, VERIFYCODE_TIMEOUT);
    }
}