前后端分离项目中验证码登录方案优化与实现指南

SpringBoot 图形验证码的生成和校验

前后端分离项目中验证码登录方案优化与实现指南

更新时间为 2021 年 05 月 27 日 14 时 57 分 02 秒,作者是盛夏温暖流年。

系统和业务在不停升级,前后端代码放在一起的项目变得越来越臃肿,已经无法做到快速迭代以及进行职责区分。于是,大家纷纷投入到前后端分离的怀抱中。当实现代码和职责分离后,开发效率越来越高。然而,以前的验证码登录方案需要进行更改。接下来,本文将来看一下 SpringBoot 图形验证码的生成和校验。

目录

1. 编写工具类

package com.cn.beauty.util;
import org.slf4j.Logger;
引入 org.slf4j.LoggerFactory 类;将 org.slf4j.LoggerFactory 类进行引入;把 org.slf4j.LoggerFactory 类给引入进来。
import javax.imageio.ImageIO;
引入 javax.servlet.http 中的 HttpServletRequest 类;
引入 javax.servlet.http.HttpServletResponse;
需要导入 javax.servlet.http 包中的 HttpSession 类。
import java.awt.*;
引入了 Java 的.awt.image 包中的 BufferedImage 类。
import java.util.ArrayList;
import java.util.Random;
公共类 RandomValidateCodeUtil 。
公共静态最终字符串 RANDOMCODEKEY 为 "MEISHANG-LOGIN-RANDOMVALIDATECODEKEY";这是放到 session 中的 key。
此字符串用于随机产生数字与字母组合的字符串。
    private int width = 95;// 图片宽
图片的高度为 40,这是一个私有整型变量,其值被设定为 40。
声明一个整型变量 stringNum,其值为 4;这个变量用于随机产生字符的数量。
Logger 被定义为私有静态常量,其值为 LoggerFactory.getLogger(RandomValidateCodeUtil.class);该 Logger 用于记录相关日志信息;它是在 RandomValidateCodeUtil 类的上下文中被创建和使用的。
有一个私有对象 random,它是通过 new Random() 创建的。
    /**
     * 获得字体
     */
    private Font getFont() {
创建一个新的字体对象,该字体使用“Wide Latin”字体族,字体样式为普通(Font.PLAIN),字体大小为 18 。
    }
    /**
     * 获得颜色(粉色为主)
     */
然后将这三个分量值组合成一个颜色对象并返回。
        ArrayList colors = new ArrayList();
颜色添加了一个新的颜色,其 RGB 值为 241、158 和 194。
颜色被添加进来,添加的是一个新的颜色,这个新颜色的 RGB 值分别为 255、94 和 226。
创建了一个新的颜色对象,其 RGB 值分别为 255、156 和 177,并将其添加到 colors 集合中。
添加了一种新的颜色,其 RGB 值为 245、152 和 217 。
创建了一个新的 Color 对象,其红色分量为 255,绿色分量为 85,蓝色分量为 81,并将其添加到 colors 中。
添加一种颜色,这种颜色是新创建的 Color(245, 152, 251);
        int num = random.nextInt(6);
        return colors.get(num);
    }
    /**
     * 生成随机图片
     */
在获取随机码时,需要使用 HttpServletRequest 请求对象和 HttpServletResponse 响应对象。首先获取请求对象,然后从请求对象中获取相关参数或信息,接着根据这些参数或信息生成随机码,最后将生成的随机码通过响应对象返回给客户端。
获取到请求对象 request ,然后通过 request 获取到会话对象 HttpSession ,即 session = request.getSession() 。
BufferedImage 类是一种带有缓冲区的 Image 类。Image 类是用来描述图像信息的类。
创建了一个 BufferedImage 对象,其宽度为 width,高度为 height,类型为 BufferedImage.TYPE_INT_BGR,该对象名为 image。
产生 Image 对象的 Graphics 对象,该 Graphics 对象为 g,它可以在图像上进行各种绘制操作。
g 用 fillRect 方法绘制一个矩形,其左上角坐标为(0, 0),宽度为 width,高度为 height,此操作用于确定图片的大小。
g 设定了一个新的字体,这个字体的名称为“Wide Latin”,字体样式为 Font.PLAIN,字体大小为 18。
设置字体颜色为获取到的随机颜色。
        // 添加噪点
        float yawpRate = 0.01f;// 噪声率
定义一个整型变量 area ,它的值等于 yawpRate 乘以 width 再乘以 height 的结果并进行强制类型转换为整型。
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            image.setRGB(x, y, random.nextInt(255));
        }
        // 绘制随机字符
        String randomString = "";
        for (int i = 1; i <= stringNum; i++) {
            randomString = drowString(g, randomString, i);
        }
        logger.info(randomString);
        //将生成的随机字符串保存到session中
        session.removeAttribute(RANDOMCODEKEY);
        session.setAttribute(RANDOMCODEKEY, randomString);
        g.dispose();
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            logger.error("将内存中的图片通过流动形式输出到客户端失败>>>>   ", e);
        }
    }
    /**
     * 绘制字符串
     */
绘制的过程中涉及到整数 i 。
        g.setFont(getFont());
        g.setColor(getRandColor());
获取随机数 `random.nextInt(randString)`,将其转换为字符串,赋值给 `rand` 。
                .length())));
        randomString += rand;
g 进行了一次翻译操作,这个操作的参数分别是两个在 0 到 2 之间(包括 0 和 2)随机生成的整数。
g 绘制字符串 rand,位置在 20 乘以(i 减 1)再加上 3 的横坐标处,纵坐标为 25。
        return randomString;
    }
    /**
     * 获取随机的字符
     */
获取一个指定长度的随机字符串。这个长度由参数 num 决定。它会生成一个包含随机字符的字符串。这些随机字符可以是字母、数字或其他可打印字符。通过特定的算法和随机数生成器来实现随机字符串的生成。
获取随机字符串中的指定位置字符,然后将其转换为字符串形式并返回。具体来说,就是获取 randString 这个随机字符串,找到其索引为 num 的位置的字符,再将该字符转换为字符串,最后返回这个字符串。
    }
}

2. 编写 Controller 中的接口

	/**
	 * @description 生成验证码
	 */
@RequestMapping 的 value 属性值为 "/user/getVerify"
公共的方法用于获取验证。该方法接收一个 HttpServletRequest 请求对象和一个 HttpServletResponse 响应对象作为参数。它的主要作用是进行与验证相关的操作,并将结果返回或进行相应的处理。
	    try {
	        //设置相应类型,告诉浏览器输出的内容为图片
response 被设置为 "image/jpeg" 这种内容类型。
	        //设置响应头信息,告诉浏览器不要缓存此内容
response 设置了一个名为 "Pragma" 的头部,其值为 "No-cache"。
response 被设置了头部信息“Cache-Control”,其值为“no-cache”。
response 设置了一个名为“Expire”的日期头,其值为 0 。
RandomValidateCodeUtil 是一个新创建的对象,名为 randomValidateCode 。
	        //输出验证码图片方法
获取随机验证码的函数 randomValidateCode 对请求和响应进行了操作,即获取了随机验证码并分别作用于请求和响应。
	    } catch (Exception e) {
	        log.error("获取验证码失败>>>>", e);
	    }
	}
	
	/**
	 * @description 校验验证码
	 */
@PostMapping 用于映射到 "/user/checkVerify" 路径
判断是否通过验证,需要传入一个名为 verifyInput 的请求参数以及一个 HttpSession 对象。如果从 session 中获取到的验证码与传入的 verifyInput 相等,则返回 true,否则返回 false。
	    try {
	        // 从session中获取随机数
verifyInput 被赋值给了 String 类型的 inputStr 。
从 session 中获取名为 "MEISHANG-LOGIN-RANDOMVALIDATECODEKEY" 的属性,其值为一个字符串,将这个字符串赋值给变量 random 。
	        if (random == null) {
	            return false;
	        }
如果 random 与 inputStr 不区分大小写地相等,那么
	            return true;
	        } else {
	            return false;
	        }
	    } catch (Exception e) {
	        log.error("验证码校验失败", e);
	        return false;
	    }
	}

3. 获取验证码图片

访问获取验证码接口

通过 127.0.0.1:8605 这个地址来获取用户的验证信息。

效果如下

另一种方法1.添加依赖


            com.github.penggle
            kaptcha
            2.3.2
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        

项目结构

2.全部代码

UserController

package com.yzm.config;
import java.util.HashMap;
引入 javax.annotation.Resource 这个注解;将 javax.annotation.Resource 进行引入;导入 javax.annotation.Resource 这个注解到代码中;把 javax.annotation.Resource 这个注解给引入进来;对 javax.annotation.Resource 进行引入操作;把 javax.annotation.Resource 这个注解引入到程序里;引入了 javax.annotation.Resource 这个注解;将 javax.annotation.Resource 这个注解予以引入;把 javax.annotation.Resource 这个注解引入到相关部分。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
使用了 Spring 框架的注解 @Controller 来标识这是一个控制器类。它在 Spring 应用程序的开发中起到了关键作用,用于处理 HTTP 请求并返回相应的视图或数据。通过这个注解,Spring 能够识别和管理该类,将其纳入到应用的请求处理流程中,实现业务逻辑的处理和页面的渲染等功能。
使用了 org.springframework.web.bind.annotation.RequestMapping 这个注解。 它用于处理 HTTP 请求映射。 可以将特定的 HTTP 请求路径与处理该请求的方法进行关联。 这样在接收到相应的 HTTP 请求时,就会调用对应的处理方法。
引入 org.springframework.web.bind.annotation.RequestParam;
引入 org.springframework.web.bind.annotation.ResponseBody ;将 org.springframework.web.bind.annotation.ResponseBody 进行引入 ;引入的是 org.springframework.web.bind.annotation.ResponseBody 。
引入 com.google.code.kaptcha.impl 包下的 DefaultKaptcha 类。
import com.yzm.utils.Util;
@Controller
public class TestControler {
 
    @Resource
有一个私有类型的 DefaultKaptcha 叫做 captchaProducer 。
    /**
     * 登录验证码SessionKey
     */
3. 公共的、静态的且最终的字符串为“login_validate_code”,其用途是登录验证码。
    /**
     * 登录验证码图片
     */
@RequestMapping 的值为 {"/loginValidateCode"}
在公共方法 loginValidateCode 中,接收了 HttpServletRequest 请求和 HttpServletResponse 响应这两个参数,并且在该方法内部会抛出异常。
Util 对请求、响应、验证码生成器以及登录验证码进行验证代码的操作,即 Util.validateCode(request, response, captchaProducer, LOGIN_VALIDATE_CODE)。
    }
 
    /**
     * 检查验证码是否正确
     */
@RequestMapping 的路径为 "/checkLoginValidateCode"
    @ResponseBody
公共的 HashMap 用于检查登录验证码。它接收一个 HttpServletRequest 请求和一个名为“validateCode”的请求参数字符串。这个方法用于验证登录相关的验证码。
从请求中获取会话,然后从会话中获取名为 LOGIN_VALIDATE_CODE 的属性,最后将该属性转换为字符串并赋值给 String 类型的 loginValidateCode 变量。
        HashMap map = new HashMap();
如果登录验证码为空。
map 将 "status" 这个键对应的值设为 null,这表示验证码已经过期。
如果 loginValidateCode 等于 validateCode ,那么
map 将 "status" 这个键与 true 值进行关联,意味着验证码是正确的。
如果 loginValidateCode 不等于 validateCode,那么就……
map 将 "status" 这个键与 false 这个值进行关联,意味着验证码不正确。
        }
        map.put("code",200);
        return map;
    }
}
package com.yzm.controller;
import java.util.Properties;
在 org.springframework.context.annotation 包中使用 @Bean 进行注解。
使用 @Component 注解的是一个 Java 类,该类属于 Spring 框架的一部分,用于标识这是一个组件。
import com.google.code.kaptcha.impl.DefaultKaptcha;
引入 com.google.code.kaptcha.util.Config 类。
@Component
public class TestConfig {
 
    @Bean
它可以用于生成验证码等相关操作。
创建了一个名为 defaultKaptcha 的 DefaultKaptcha 对象。
创建了一个 Properties 类的实例,名为 properties 。
        // 图片边框
properties 让 "kaptcha.border" 的属性值为 "no";
        // 边框颜色
properties 让 "kaptcha.border.color" 属性的值为 "black" 。
        //边框厚度
properties 令 "kaptcha.border.thickness" 属性等于 "1" 。
        // 图片宽
properties 将 "kaptcha.image.width" 属性设置为 "200"。
        // 图片高
设置属性"kaptcha.image.height"的值为"50"。
        //图片实现类
properties 令 "kaptcha.producer.impl" 属性的值为 "com.google.code.kaptcha.impl.DefaultKaptcha"。
        //文本实现类
properties 将 "kaptcha.textproducer.impl" 属性设置为 "com.google.code.kaptcha.text.impl.DefaultTextCreator"。
        //文本集合,验证码值从此集合中获取
properties 把 "kaptcha.textproducer.char.string" 属性设置为 "01234567890" ;
        //验证码长度
properties 将“kaptcha.textproducer.char.length”属性设置为“4”。
        //字体
properties 把“kaptcha.textproducer.font.names”这个属性设置为“宋体”。
        //字体颜色
properties 将 "kaptcha.textproducer.font.color" 属性设置为 "black"。
        //文字间隔
properties 将 "kaptcha.textproducer.char.space" 属性设置为 "5"。
        //干扰实现类
properties 将 "kaptcha.noise.impl" 属性设置为 "com.google.code.kaptcha.impl.DefaultNoise" 。
        //干扰颜色
properties 将 "kaptcha.noise.color" 属性设置为 "blue"。
        //干扰图片样式
properties 将 "kaptcha.obscurificator.impl" 属性设置为 "com.google.code.kaptcha.impl.WaterRipple"。
        //背景实现类
properties 将 "kaptcha.background.impl" 属性设置为 "com.google.code.kaptcha.impl.DefaultBackground"
        //背景颜色渐变,结束颜色
properties 将 "kaptcha.background.clear.to" 属性设置为 "white"。
        //文字渲染器
properties 将 "kaptcha.word.impl" 属性设置为 "com.google.code.kaptcha.text.impl.DefaultWordRenderer"
创建了一个名为 config 的对象,该对象是通过 new Config(properties) 语句创建的。
defaultKaptcha 把配置(config)进行了设置。
        return defaultKaptcha;
    }
 
}

Util

package com.yzm.utils;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
导入 javax.servlet.ServletOutputStream 类。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.code.kaptcha.impl.DefaultKaptcha;
public class Util {
     
    /**
     * 生成验证码图片
     * @param request 设置session
     * @param response 转成图片
参数 captchaProducer 为生成图片的方法类。
参数为 validateSessionKey ,它是一个 session 名称。
     * @throws Exception
     */
静态的 void 方法 validateCode,它接受 HttpServletRequest 请求、HttpServletResponse 响应、DefaultKaptcha 验证码生成器以及字符串 validateSessionKey 作为参数,并抛出异常。
设置为在很久以前就过期。
response 设置了名为 "Expires" 的日期头,将其值设置为 0 。
设置标准的 HTTP/1.1 无缓存头。
response 设置了头部信息“Cache-Control”,其值为“no-store, no-cache, must-revalidate”。
response 为响应对象,它添加了一个名为 "Cache-Control" 的头部信息,该头部信息的值为 "post-check=0, pre-check=0" 。
设置标准的 HTTP/1.0 无缓存头。
response 为响应对象,通过该对象设置了名为 "Pragma" 的头部信息,其值为 "no-cache" 。
 
        // return a jpeg
设置响应的内容类型为“image/jpeg”。
 
创建用于该图像的文本。
captchaProducer 生成了字符串 capText 。
 
将文本存储在会话中。
获取到的 session 调用 setAttribute 方法,将 validateSessionKey 作为键,capText 作为值进行设置。即通过 request 获取到的 session 把 validateSessionKey 这个键与 capText 这个值关联起来。
 
使用这段文字来创建图像。
BufferedImage bi 是由 captchaProducer 创建的图像,创建的内容为 capText 。
 
response 获取到输出流,该输出流为 ServletOutputStream 类型,记为 out 。
 
        // write the data out
使用 ImageIO 将 bi 写入为 "jpg" 格式并输出到 out 中。
        try {
            out.flush();
        } finally {
            out.close();
        }
    }
}

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读