Springboot 验证码生成和校验,图片格式和base64编码串

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: Springboot 验证码生成和校验,图片格式和base64编码串

开始敲代码前,先简单介绍下大致的想法实现:


生成验证码:

提供一个接口, 这个接口里,我们将生成的验证码存入session,然后将验证码以图片格式或者base64编码串返回给调用端。


校验验证码:

提供一个接口,这个接口里,我们收到调用端传过来的校验码,然后从session取出验证码,两个验证码都全部转小写,进行无大小写区分匹配校验,返回true/flase 。


存储验证码:

生成的验证码,在未生成图片的时候,就将4位验证码字符先存入session,以‘JCCODE’作为存取session的key。


OK,不废话,开始敲代码:


首先创建工具类,ValidateCodeUtil.java:

可以看注释,里面包含了设置验证码图片的宽高,干扰线数量,验证码个数;返回图片,返回base6编码串,存入session域等等。


import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.Random;
/**
 * @Author : JCccc
 * @CreateTime : 2019/9/25
 * @Description :
 **/
public class ValidateCodeUtil {
    private static Random random = new Random();
    private int width = 165; //验证码的宽
    private int height = 45; //验证码的高
    private int lineSize = 30; //验证码中夹杂的干扰线数量
    private int randomStrNum = 4; //验证码字符个数
    private String randomString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ";
    private final String sessionKey = "JCCODE";
    //字体的设置
    private Font getFont() {
        return new Font("Times New Roman", Font.ROMAN_BASELINE, 40);
    }
    //颜色的设置
    private static Color getRandomColor(int fc, int bc) {
        fc = Math.min(fc, 255);
        bc = Math.min(bc, 255);
        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 12);
        return new Color(r, g, b);
    }
    //干扰线的绘制
    private void drawLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(20);
        int yl = random.nextInt(10);
        g.drawLine(x, y, x + xl, y + yl);
    }
    //随机字符的获取
    private  String getRandomString(int num){
        num = num > 0 ? num : randomString.length();
        return String.valueOf(randomString.charAt(random.nextInt(num)));
    }
    //字符串的绘制
    private String drawString(Graphics g, String randomStr, int i) {
        g.setFont(getFont());
        g.setColor(getRandomColor(108, 190));
        //System.out.println(random.nextInt(randomString.length()));
        String rand = getRandomString(random.nextInt(randomString.length()));
        randomStr += rand;
        g.translate(random.nextInt(3), random.nextInt(6));
        g.drawString(rand, 40 * i + 10, 25);
        return randomStr;
    }
    //生成随机图片
    public void getRandomCodeImage(HttpServletRequest request, HttpServletResponse response){
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);
        g.setColor(getRandomColor(105, 189));
        g.setFont(getFont());
        // 干扰线
        for (int i = 0; i < lineSize; i++) {
            drawLine(g);
        }
        // 随机字符
        String randomStr = "";
        for (int i = 0; i < randomStrNum; i++) {
            randomStr = drawString(g, randomStr, i);
        }
        System.out.println("随机字符:"+randomStr);
        g.dispose();
        //移除之前的session中的验证码信息
        session.removeAttribute(sessionKey);
        //重新将验证码放入session
        session.setAttribute(sessionKey, randomStr);
        try {
            //  将图片以png格式返回,返回的是图片
            ImageIO.write(image, "PNG", response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     //生成随机图片的base64编码字符串
    public String getRandomCodeBase64(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);
        g.setColor(getRandomColor(105, 189));
        g.setFont(getFont());
        //干扰线
        for (int i = 0; i < lineSize; i++) {
            drawLine(g);
        }
        //随机字符
        String randomStr = "";
        for (int i = 0; i < randomStrNum; i++) {
            randomStr = drawString(g, randomStr, i);
        }
        System.out.println("随机字符:"+randomStr);
        g.dispose();
        session.removeAttribute(sessionKey);
        session.setAttribute(sessionKey, randomStr);
        String base64String = "";
        try {
            //  直接返回图片
            //  ImageIO.write(image, "PNG", response.getOutputStream());
            //返回 base64
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ImageIO.write(image, "PNG", bos);
            byte[] bytes = bos.toByteArray();
            Base64.Encoder encoder = Base64.getEncoder();
            base64String = encoder.encodeToString(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return base64String;
    }
    }


接下来写接口,创建一个ValidateCodeController.java,

先是生成验证码,返回图片的接口:


import com.example.demo.util.ValidateCodeUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
 * @Author : JCccc
 * @CreateTime : 2019/9/25
 * @Description :
 **/
@RestController
public class ValidateCodeController {
    //返回验证码图片
   @GetMapping("/getCaptchaImg")
   public void getCaptchaImg(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
       try {
           response.setContentType("image/png");
           response.setHeader("Cache-Control", "no-cache");
           response.setHeader("Expire", "0");
           response.setHeader("Pragma", "no-cache");
           ValidateCodeUtil validateCode = new ValidateCodeUtil();
           // getRandomCodeImage方法会直接将生成的验证码图片写入response
           validateCode.getRandomCodeImage(request, response);
           // System.out.println("session里面存储的验证码为:"+session.getAttribute("JCCODE"));
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}


用postman来调用下接口,


image.png可以看到控制台的打印,这个验证码字符串已经存入了session(在后面的验证接口有介绍取值)


image.png


OK,接下来是编写一个校验验证码接口:


    //验证码校验
    @GetMapping("/checkCaptcha")
    public boolean getCheckCaptcha(@RequestParam("code") String code, HttpSession session) {
        try {
            //toLowerCase() 不区分大小写进行验证码校验
            String sessionCode= String.valueOf(session.getAttribute("JCCODE")).toLowerCase();
            System.out.println("session里的验证码:"+sessionCode);
            String receivedCode=code.toLowerCase();
            System.out.println("用户的验证码:"+receivedCode);
            return !sessionCode.equals("") && !receivedCode.equals("") && sessionCode.equals(receivedCode);
        } catch (Exception e) {
            return false;
        }
    }


用postman调下接口,先生成验证码模拟返回给页面了,


image.png


然后调用校验验证码接口,模拟用户在页面输入验证码,


image.pngimage.png


可以看到校验正确。


最后,再补一个返回base64编码串的接口,


    // 生成验证码,返回的是 base64
    @GetMapping("/getCaptchaBase64")
    public Object getCaptchaBase64(HttpServletRequest request, HttpServletResponse response) {
        Map result = new HashMap();
        try {
            response.setContentType("image/png");
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Expire", "0");
            response.setHeader("Pragma", "no-cache");
            ValidateCodeUtil validateCode = new ValidateCodeUtil();
            // 返回base64
            String base64String = validateCode.getRandomCodeBase64(request, response);
            result.put("url", "data:image/png;base64," + base64String);
            result.put("message", "created successfull");
           //http://tool.chinaz.com/tools/imgtobase/  base64直接转为图片网站
            System.out.println("结果:" + result.get("url"));
        } catch (Exception e) {
            System.out.println(e);
        }
        return result;
    }


用postman调用一下,


image.png


控制台打印:


image.png


将url取出来,


data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKUAAAAtCAIAAABAqjw4AAACjklEQVR42u3bzW7DIAwHcB57x0l7hG67TVp37juySpFQlPDxj21sKEacWrRQfhDAsBDh9H372HIcJj3+vp45eoJTmNp7r+7wq3if4d1+Yu/74w3PPugX9fY5fkpvJranKb2liq25HdjXmeWdPunXD56KzSZWHt+VlcGwHSJVjO59wO6hvhGC3uPs/gW3Ce/32zML9lGKd9a130AHvfetXMr6u3/aczfmlI3n75KoCfnhZW64BZd66AHb3lt/Tdf0fsnAyyVv8Jf28lZbxtcn76nhS96lRYPNfkzTG1+Zz6h+yRskfwVvweXVln4/f7IZL5At5t4G3jh8kwq0JEi7d8cwS0W9yYkUUHufI+TTe3fdTbl3A/L5vEox2eWSQlgNeWM33/mC3s19udn45uwRNV/mODmhAAf77H2Ow1wd/cLe+8HN2SMOMrjB4VtfnwsG2irf2ninMtsjzzPijN7ICFbwphWQ8a7HzyuBLSlv5QPQJme2ABM7YvHUjt518soaLTHLeqvFuZDhm43JaHqD5IFQD8Kxt2w4c38AijyUfzDa5DwU4GPjY7e7N3OPy4QvHYCSa4J0Bdw7zegjeJ9/jrY3EtWivcy7HocgnGTvUodjemcbxMybjGR1ewn3Zg7uBC8yvg/NG+JUyfDqMT/WZvU+J95PbXZJNW+r3pY4S3P/mN6Rdj91HHVbb06Bft7IBHrtfurV6WdBb6mVuVS8RXW95v+xV98BCnrjNyCC2k8dsN35ZrJ/7WrsbP8VeEAV9Bt6zDEnZS9bwyz59pTsh2PFW1ZY1vWwR469o/j9NU+jdSz3Xp3cvZ3cvRcmd++1yMPg/dGTbKsGq8q5ugl5sK2fqyuT29xncnXlBk/5HyEm10e/qyfBAAAAAElFTkSuQmCC


去base64编码串转图片的网站去看看,对应的验证码图:


image.png


OK,生成验证码和校验的相关教程到此结束。

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
3月前
|
C#
C# 图形验证码实现登录校验代码
C# 图形验证码实现登录校验代码
113 2
|
4月前
|
前端开发 PHP
ThinkPHP 验证码扩展库的使用,以及多应用模式下,如何自定义验证码校验规则
本文介绍了在ThinkPHP框架中使用验证码扩展库的方法,包括安装验证码扩展库、在页面中使用验证码、自定义验证码配置以及校验验证码的步骤和代码示例。
ThinkPHP 验证码扩展库的使用,以及多应用模式下,如何自定义验证码校验规则
|
5月前
|
SQL 前端开发 NoSQL
SpringBoot+Vue 实现图片验证码功能需求
这篇文章介绍了如何在SpringBoot+Vue项目中实现图片验证码功能,包括后端生成与校验验证码的方法以及前端展示验证码的实现步骤。
SpringBoot+Vue 实现图片验证码功能需求
|
6月前
|
Java Spring
springBoot 使用 @NotEmpty,@NotBlank,@NotNull 及@Valid注解校验请求参数
springBoot 使用 @NotEmpty,@NotBlank,@NotNull 及@Valid注解校验请求参数
291 7
|
5月前
|
NoSQL Java Redis
认证服务---整合短信验证码,验证码倒计时,验证码防刷校验 【一】
这篇文章介绍了如何在分布式微服务项目中整合短信验证码服务,包括使用阿里云短信验证接口、将短信验证功能集成到第三方服务中、其他服务的远程调用,以及通过Redis实现验证码防刷机制的代码实现和遇到的问题解决方案。
|
5月前
|
NoSQL JavaScript Java
SpringBoot+Vue+Redis实现验证码功能、一个小时只允许发三次验证码。一次验证码有效期二分钟。SpringBoot整合Redis
这篇文章介绍了如何使用SpringBoot结合Vue和Redis实现验证码功能,包括验证码的有效期控制和一小时内发送次数的限制。
|
6月前
|
文字识别 Java Spring
文本,文字识别,SpringBoot服务开发,SpringBoot如何提供上传服务,接口的设计,它做了将Base64重新转为图片,SpringBoot的应用实例,项目基础搭建
文本,文字识别,SpringBoot服务开发,SpringBoot如何提供上传服务,接口的设计,它做了将Base64重新转为图片,SpringBoot的应用实例,项目基础搭建
|
7月前
|
Java
springboot自定义拦截器,校验token
springboot自定义拦截器,校验token
501 6
|
7月前
|
缓存 NoSQL Java
案例 采用Springboot默认的缓存方案Simple在三层架构中完成一个手机验证码生成校验的程序
案例 采用Springboot默认的缓存方案Simple在三层架构中完成一个手机验证码生成校验的程序
126 5
|
7月前
|
XML 前端开发 Java
SpringBoot参数校验@Validated、@Valid(javax.validation)详解
SpringBoot参数校验@Validated、@Valid(javax.validation)
1040 4