系列十、Spring Security登录接口添加验证码

news2025/1/31 8:21:58

一、Spring Security登录接口添加验证码

1.1、概述

        一般企业开发中,登录时都会有一个验证码,基于Spring Security的登录接口默认是没有验证码的?那么如何把验证码功能集成到Spring Security的登录接口呢?请看下文!

1.2、生成验证码

1.2.1、 VerifyCode7006

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2024/1/12 17:31
 * @Description: 验证码实体类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@ToString(callSuper = true)
public class VerifyCode7006 {

    /**
     * 生成验证码图片的宽度
     */
    private Integer width = 100;

    /**
     * 生成验证码图片的高度
     */
    private Integer height = 50;

    /**
     * 字体集合
     */
    private String[] fontNames = {"宋体", "楷体", "隶书", "微软雅黑"};

    /**
     * 定义验证码图片的背景颜色为白色
     */
    private Color bgColor = new Color(255, 255, 255);

    /**
     * 定义随机数
     */
    private Random random = new Random();

    /**
     * 混淆代码
     * confuse:混淆
     */
    private String confuseCode = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /**
     * 记录随机生成的验证码
     */
    private String code;

    /**
     * 获取一个随意颜色
     *
     * @return
     */
    private Color randomColor() {
        int red = random.nextInt(150);
        int green = random.nextInt(150);
        int blue = random.nextInt(150);
        return new Color(red, green, blue);
    }

    /**
     * 获取一个随机字体
     *
     * @return
     */
    private Font randomFont() {
        String name = fontNames[random.nextInt(fontNames.length)];
        int style = random.nextInt(4);
        int size = random.nextInt(5) + 24;
        return new Font(name, style, size);
    }

    /**
     * 获取一个随机字符
     *
     * @return
     */
    private char randomChar() {
        return confuseCode.charAt(random.nextInt(confuseCode.length()));
    }

    /**
     * 创建一个空白的BufferedImage对象
     *
     * @return
     */
    private BufferedImage createImage() {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) image.getGraphics();
        /**
         * 设置验证码图片的背景颜色
         */
        g2.setColor(bgColor);
        g2.fillRect(0, 0, width, height);
        return image;
    }

    public BufferedImage getImage() {
        BufferedImage image = createImage();
        Graphics2D g2 = (Graphics2D) image.getGraphics();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4; i++) {
            String s = randomChar() + "";
            sb.append(s);
            g2.setColor(randomColor());
            g2.setFont(randomFont());
            float x = i * width * 1.0f / 4;
            g2.drawString(s, x, height - 15);
        }
        this.code = sb.toString();
        // drawLine(image);
        return image;
    }

    /**
     * 绘制干扰线
     *
     * @param image
     */
    private void drawLine(BufferedImage image) {
        Graphics2D g2 = (Graphics2D) image.getGraphics();
        int num = 5;
        for (int i = 0; i < num; i++) {
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            g2.setColor(randomColor());
            g2.setStroke(new BasicStroke(1.5f));
            g2.drawLine(x1, y1, x2, y2);
        }
    }

}

1.2.2、VerifyCodeUtil7006

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2024/1/12 18:18
 * @Description: 验证码工具类
 */
public class VerifyCodeUtil7006 {

    /**
     * 获取验证码的image 和 text
     * @return
     */
    public static Map<String,Object> initVerifyCode() {
        Map<String,Object> verifyCodeMap = new HashMap<>(2);
        VerifyCode7006 vc = new VerifyCode7006();
        BufferedImage image = vc.getImage();
        String code = vc.getCode();
        verifyCodeMap.put("image",image);
        verifyCodeMap.put("code",code);

        return verifyCodeMap;
    }

    /**
     * 输出验证码
     * @param image
     * @param out
     * @throws IOException
     */
    public static void output(BufferedImage image, OutputStream out) throws IOException {
        ImageIO.write(image, "JPEG", out);
    }

}

1.2.3、VerifyCodeController7006

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2024/1/12 22:28
 * @Description:
 */
@RequestMapping("/verifyCode")
@RestController
public class VerifyCodeController7006 {

    /**
     * 获取验证码
     *
     * @param request
     * @param response
     */
    @GetMapping("/getVerifyCode")
    public void getVerifyCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, Object> verifyCodeMap = VerifyCodeUtil7006.initVerifyCode();
        BufferedImage image = (BufferedImage) verifyCodeMap.get("image");
        String code = (String) verifyCodeMap.get("code");
        HttpSession session = request.getSession();
        session.setAttribute("code", code);
        VerifyCodeUtil7006.output(image,response.getOutputStream());
    }

}

1.3、配置类(核心部分)

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);
	http.authorizeRequests()
			.antMatchers("/dba/**").hasRole("dba")
			.antMatchers("/admin/**").hasRole("admin")
			.antMatchers("/helloWorld","/verifyCode/getVerifyCode")
			.permitAll()
			.anyRequest()
			.authenticated()

			.and()

			/**
			 * 登录成功 & 登录失败回调
			 */
			.formLogin()
			.loginPage("/login")
			.successHandler(successHandler)
			.failureHandler(failureHandler)

			.and()

			/**
			 * 注销登录回调
			 */
			.logout()
			.logoutUrl("/logout")
			.logoutSuccessHandler(logoutSuccessHandler)
			.permitAll()

			.and()

			.csrf()
			.disable()

			/**
			 * 未认证 & 权限不足回调
			 */
			.exceptionHandling()
			.authenticationEntryPoint(authenticationEntryPoint)
			.accessDeniedHandler(accessDeniedHandler);
}

1.4、过滤器

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2024/1/12 19:49
 * @Description: 自定义验证码过滤器
 * 作用:
 *      自定义过滤器继承自 GenericFilterBean,并实现其中的 doFilter 方法,在 doFilter 方法中,当请求方法是 POST,
 * 并且请求地址是 /login 时,获取参数中的 code 字段值,该字段保存了用户从前端页面传来的验证码,然后获取 session 中保存的验证码,
 * 如果用户没有传来验证码,则抛出验证码不能为空异常,如果用户传入了验证码,则判断验证码是否正确,如果不正确则抛出异常,
 * 否则执行 chain.doFilter(request, response); 使请求继续向下走。
 */
@Slf4j
@Component
public class MyVerifyCodeFilter extends GenericFilterBean {

    private static final String DEFAULT_FILTER_PROCESS_URL = "/login";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession session = request.getSession();
        log.info("session:{}", session);
        if (HttpMethod.POST.name().equalsIgnoreCase(request.getMethod()) && DEFAULT_FILTER_PROCESS_URL.equals(request.getServletPath())) {
            String paramCode = request.getParameter("code");
            String sessionCode = (String) session.getAttribute("code");
            log.info("paramCode:{},sessionCode:{}", paramCode, sessionCode);
            if (StringUtils.isBlank(paramCode)) {
                R r = R.error(ResponseEnum.VERIFY_CODE_IS_NULL.getCode(), ResponseEnum.VERIFY_CODE_IS_NULL.getMessage());
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                out.write(new ObjectMapper().writeValueAsString(r));
                out.flush();
                out.close();
            }
            if (StringUtils.isBlank(sessionCode)) {
                R r = R.error(ResponseEnum.VERIFY_CODE_IS_EXPIRED.getCode(), ResponseEnum.VERIFY_CODE_IS_EXPIRED.getMessage());
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                out.write(new ObjectMapper().writeValueAsString(r));
                out.flush();
                out.close();
            }
            if (!StringUtils.equals(paramCode.toLowerCase(), sessionCode.toLowerCase())) {
                R r = R.error(ResponseEnum.VERIFY_CODE_IS_NOT_MATCH.getCode(), ResponseEnum.VERIFY_CODE_IS_NOT_MATCH.getMessage());
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                out.write(new ObjectMapper().writeValueAsString(r));
                out.flush();
                out.close();
            }
        }
        chain.doFilter(request, response);
    }
}

1.5、测试

1.5.1、生成验证码

1.5.2、登录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1383327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot视图渲染技术:整合Freemarker,常见指令和数据类型

目录 1.Freemarker 1.1.什么是Freemarker 1.2.Freemarker模板组成部分 1.3.优点 2.SpringBoot整合Freemarker 2.1.配置 2.2.数据类型 2.2.1.字符串 2.2.2.数值 2.2.3.布尔值 2.2.4.日期 2.3.常见指令 2.3.1.处理不存在的值 2.3.2.assign 2.3.3.if/elseif/else …

物联网中的通信技术

阅读引言&#xff1a; 本文主要大致为大家带来物联网中的常见的通信方式的知识梳理。 目录 一、概述 二、无线通信技术 1.物联网电子标签 RFID 1.1 RFID 概念 1.2 RFID 系统组成 2.WI-FI技术 3.UWB技术 4.ZigBee技术 5.NFC技术 6.蓝牙技术 7.EnOcean技术 一、概述 物…

ssm基于VUE.js的在线教育系统论文

摘 要 随着学习压力越来越大&#xff0c;课外参加补习班的学生越来越多。现在大多数学生采用请家教、自学、报名补习班的方式进行课外的额外学习。请家教费用昂贵&#xff0c;自学效率低&#xff0c;碰到自己不会的知识不能及时得到解达&#xff0c;报名补习班需要时间、地点的…

VBA技术资料MF106:检查单元格是否在表对象中

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

Java中的包机制、final和super关键字

一、包机制 关于java语言当中的包机制&#xff1a; 1.包又被称为package,java中引入package这种语法机制主要是为了方便程序的管理。 不同功能的类被分门别类放到不同的软件包当中&#xff0c;查找比较方便&#xff0c;管理比较方便&#xff0c;易维护。 2.怎么定义package呢…

第 4 课 创建工作空间与功能包

文章目录 第 4 课 创建工作空间与功能包1.工作环境的创建2.ROS功能包的创建 第 4 课 创建工作空间与功能包 消息和服务的创建、发布器和订阅器的编写、服务端和客户端的编写都是基于Ros功能包进行操作的&#xff0c;因此在进行上述操作前&#xff0c;需要先创建工作空间及功能包…

基于Springboot的网上点餐系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的网上点餐系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&am…

【Java学习】Java环境变量——配置jdk

本文我主要是介绍jdk的下载方式和在Windows系统下安装配置jdk11&#xff08;压缩包格式&#xff09;&#xff0c;其他格式的jdk以及Linux操作系统上的jdk安装我后续视情况进行更新… JDK的下载 大家可以去官网Java|Oracle下载对应的资源&#xff0c;也可以下载文末我上传的jd…

8 - MySQL数据读写分离|MySQL多实例

MySQL数据读写分离&#xff5c;MySQL多实例 MySQL数据读写分离数据读写分离如何实现数据的读写分离提供数据读写分离服务的软件&#xff08;中间件&#xff09;maxscale 软件提供的读写分离服务的工作过程配置数据读写分离结构 提供数据存储服务 MySQL多实例 MySQL数据读写分离…

最新国内可用GPT4、Midjourney绘画、DALL-E3文生图模型教程

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

Zabbix监控系统及部署

目录 前言 一个完整的项目 业务架构 运维架构 优秀监控软件的好处 1.zabbix概述 zabbix是什么 zabbix监控原理 Zabbix6.0新特性 1.Zabbix server高可用防止硬件故障或计划维护期的停机 2.Zabbix6.0 LTS新增Kubernetes监控功能&#xff0c;可以在Kubernetes系统从多个…

选择服务商搭建WiFi贴码小程序,有哪些注意事项呢?

随着移动互联网的快速发展&#xff0c;共享WiFi已经成为人们生活中不可或缺的一部分。在各种公共场所&#xff0c;如咖啡厅、餐厅、酒店、商场等&#xff0c;提供免费WiFi已经成为一种趋势。而WiFi贴码小程序的出现&#xff0c;为商家和用户提供了一个便捷的连接方式。那么&…

多语言历史报纸广告事件抽取(ACL2023)

1、写作动机&#xff1a; 首先&#xff0c;获取大规模的、有注释的历史数据集是困难的&#xff0c;因为只有领域专家才能可靠地为它们打标签。其次&#xff0c;大多数现成的NLP模型是在现代语言文本上训练的&#xff0c;这使得它们在应用于历史语料库时效果显著降低。这对于研…

2024年《一个项目征服Java中高级体系》博客计划

终于下决心来写一套大型的Java 笔记&#xff0c;不为别的&#xff0c;就是为了强迫自己将整个Java体系梳理清楚&#xff0c;让自己成为内功扎实的Java高级架构师。牛已经吹出来了&#xff0c;不做对不起网友&#xff01; 经过一个多月的持续规划&#xff0c;现在终于定好了整体…

调用Clarifai API提取图像特征

官方文档放前面&#xff1a;Images | Clarifai Guide 功能很多&#xff0c;有各种不同的模型&#xff0c;可以提取不同的图像特征&#xff0c;比如图像摘要、图像实体等。。。 具体的调用过程&#xff1a; 1.进入官方网站Full Stack AI Developer Platform: Production Compu…

FPGA 移位运算与乘法

题目&#xff1a; 已知d为一个8位数&#xff0c;请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效&#xff08;d给出的信号的上升沿表示写入有效&#xff09; 由题意可知&#xff1a; 复位信号高有效&#xff0c;低复位&#xff1b;在inpu_grant上升…

关于编程的一些小小记录

这里记录一些关于编程的小技巧吧&#xff0c;算是个记录 1&#xff0c;vs同时有多个cpp文件怎么办&#xff1f; 我们只想运行第一个cpp文件&#xff0c;那么怎么做呢&#xff1f; 其实很简单&#xff0c;单击你不想让之运行的文件&#xff0c;点击最下面的属性 最后设置为这样…

数学建模day15-时间序列分析

时间序列也称动态序列&#xff0c;是指将某种现象的指标数值按照时间顺序排列而成的数值序列。时间序列分析大致可分成三大部分&#xff0c;分别是描述过去、分析规律和预测未来&#xff0c;本讲将主要介绍时间序列分析中常用的三种模型&#xff1a;季节分解、指数平滑方法和AR…

最小花费-银行转账-图的最短路-超详细解析注释

最小花费-银行转账-图的最短路-超详细解析注释 【题目描述】 在n个人中&#xff0c;某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费&#xff0c;请问A最少需要多少钱使得转账后B收到100元。 …

【Linux】Ubuntu 解压 zip、z01、z02等压缩文件的方法,Linux如何解压分卷压缩的

zip分卷压缩&#xff0c;在windows上压缩来的&#xff0c;如何解压这种文件&#xff1a; -rw-rw-r-- 1 20401094656 Dec 10 20:06 FFHQ.z01 -rw-rw-r-- 1 20401094656 Dec 10 20:10 FFHQ.z02 -rw-rw-r-- 1 20401094656 Dec 10 23:22 FFHQ.z03 -rw-rw-r-- 1 20401094656 Dec 10…