程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Spring Security -- 添加图形验证码(转载)

添加验证码大致可以分为三个步骤:

  • 根据随机数生成验证码图片;
  • 将验证码图片显示到登录页面;
  • 认证流程中加入验证码校验。

Spring Security的认证校验是由UsernamePasswordAuthenticationFilter过滤器完成的,所以我们的验证码校验逻辑应该在这个过滤器之前。下面一起学习下如何在上一节Spring Security自定义用户认证的基础上加入验证码校验功能。

一、生成校验码

1、导入依赖

验证码功能需要用到spring-social-config依赖:

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-config</artifactId>
    <version>1.1.6.RELEASE</version>
</dependency>

2、ImageCode实体类

在com.zy.example.entity包下创建类ImageCode:

复制代码
package com.zy.example.entity;

import lombok.Data;

import java.awt.image.BufferedImage;
import java.time.LocalDateTime;

/**
 * @Author: zy
 * @Description: 验证码
 * @Date: 2020-2-9
 */
@Data
public class ImageCode {

    /**
     * 验证码图片
     */
    private BufferedImage image;

    /**
     * code验证码
     */
    private String code;

    /**
     * 过期时间 单位秒
     */
    private LocalDateTime expireTime;

    /**
     * 判断验证码是否过期
     * @return
     */
    public boolean isExpire() {
        return LocalDateTime.now().isAfter(expireTime);
    }

    /**
     * 构造函数
     * @param image
     * @param code
     * @param expireIn
     */
    public ImageCode(BufferedImage image, String code, int expireIn) {
        this.image = image;
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
    }

}
复制代码

ImageCode对象包含了三个属性:image图片,code验证码和expireTime过期时间。isExpire方法用于判断验证码是否已过期。

3、ValidateCodeController

接着在包com.zy.example.controller下定义一个ValidateCodeController,用于处理生成验证码请求:

复制代码
package com.zy.example.controller;

import com.zy.example.entity.ImageCode;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

/**
 * @Author: zy
 * @Description: 处理生成验证码的请求
 * @Date: 2020-2-9
 */
@RestController
@RequestMapping("/code")
public class ValidateCodeController {

    public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE";

    //使用sessionStrategy将生成的验证码对象存储到Session中,并通过IO流将生成的图片输出到登录页面上。
    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

    @RequestMapping("/image")
    public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //生成验证码对象
        ImageCode imageCode = createImageCode();
        //生成的验证码对象存储到Session中
        sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY_IMAGE_CODE,imageCode);
        //通过IO流将生成的图片输出到登录页面上
        ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream());
    }

    /**
     * 用于生成验证码对象
     * @return
     */
    private ImageCode createImageCode() {

        int width = 100;    // 验证码图片宽度
        int height = 36;    // 验证码图片长度
        int length = 4;     // 验证码位数
        int expireIn = 60;  // 验证码有效时间 60s

        //创建一个带缓冲区图像对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //获得在图像上绘图的Graphics对象
        Graphics g = image.getGraphics();

        Random random = new Random();

        //设置颜色、并随机绘制直线
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);
        g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 155; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }

        //生成随机数 并绘制
        StringBuilder sRand = new StringBuilder();
        for (int i = 0; i < length; i++) {
            String rand = String.valueOf(random.nextInt(10));
            sRand.append(rand);
            g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
            g.drawString(rand, 13 * i + 6, 16);
        }
        g.dispose();
        return new ImageCode(image, sRand.toString(), expireIn);
    }

    /**
     * 获取随机演示
     * @param fc
     * @param bc
     * @return
     */
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

}
复制代码

createImageCode方法用于生成验证码对象,org.springframework.social.connect.web.HttpSessionSessionStrategy对象封装了一些处理Session的方法,包含了setAttribute、getAttribute和removeAttribute方法,具体可以查看该类的源码。使用sessionStrategy将生成的验证码对象存储到Session中,并通过IO流将生成的图片输出到登录页面上。

由于现在鉴权体系有一部分是采用无状态的jwt来实现,而没有使用Cookie、Session这种。那我们可以考虑将生成的验证码保存到redis中,而redis的key选用我们的token即可,具体实现就不介绍了,有兴趣自己研究一下。

生成验证码的方法写好后,接下来开始改造登录页面。

二、登录页

在登陆页面login.ftl追加如下代码:

<input type="text" name="imageCode" placeholder="验证码" style="width: 50%;"/>
<img src="/code/image"/>
 <br>

<img>标签的src属性对应ValidateController的createImageCode方法:

要使生成验证码的请求不被拦截,需要在BrowserSecurityConfig的configure方法中配置免拦截:

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(2589)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示