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

一、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、登录

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM的仓库在线管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

C++学习笔记——输入、输出和文件

目录 一、标准输入输出 2.1下面是它们的基本用法 解释 二、格式化输入输出 2.2下面是一个示例 解释 三、文件读写 3.3下面是一个文件读写的示例 解释 四、异常处理和错误检测 4.1下面是一个示例 解释 五、一个实例代码 5.1如何读取 CSV 文件&#xff0c;并计算每…

大厂是怎么做支付系统的流程容错的?

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 1 单据关联 如某些订单域内部的多种单据间存在关联关系一样&#xff0c;支付设计上也有单据间关联设计。如所有逆向过程都须持有正向的单据&#xff0c;因此退款须关联到原来的支付&#…

LTESniffer:一款功能强大的LTE上下行链路安全监控工具

关于LTESniffer LTESniffer是一款功能强大的LTE上下行链路安全监控工具&#xff0c;该工具是一款针对LTE的安全开源工具。 该工具首先可以解码物理下行控制信道&#xff08;PDCCH&#xff09;并获取所有活动用户的下行链路控制信息&#xff08;DCI&#xff09;和无线网络临时…

为了这口醋,包的这饺子。为了Selenium,学有限的CSS,逐步替换XPATH

Learn about CSS rules and pseudo-classes to help you move your XPATH locators to CSS. 1. 最基本IdElement TypeDirect ChildChild or Sub-ChildClass 2. 深入一点Next SiblingAttribute ValuesChoosing a Specific Match Sub-String Matches 3 参考资料 In order for Sel…

Java零基础教学文档第五篇:jQuery

今日新篇章 【jQuery】 【主要内容】 jQuery简介 jQuery安装 jQuery语法 jQuery选择器 jQuery事件处理 jQueryDOM操作 jQuery元素遍历 jQuery过滤 jQuery其它方法 【学习目标】 1.jQuery简介 1.1 jQuery简介 jQuery 库可以通过一行简单的标记被添加到网页中。 1.…

java自动化将用例和截图一起执行测试放入world中直接生成测试报告【搬代码】

1.首先我们得用例写好之后放入文档中&#xff0c;把不用的案例类型、前置条件去掉之后&#xff0c;如图&#xff1a; 放到桌面后&#xff0c;先看执行结果&#xff1a; 直接上代码 package com.znzdh.qitagongju;import jxl.Sheet; import jxl.Workbook; import org.apache…

了解集群,以及集群是什么?

每个集群即一个独立运行的文档数据库&#xff0c;分片集群架构由路由&#xff08;mongos&#xff09;、配置&#xff08;config&#xff09;和分片&#xff08;shard&#xff09;组成。 数据读写请求经mongos分发&#xff0c;通过查询config信息&#xff0c;并行分配到相应sha…

C语言之字符串和指针

目录 用数组实现的字符串和用指针实现的字符串 █用数组实现的字符串str █用指针实现的字符串ptr 注意 用数组和指针实现字符串的不同点 字符串数组 用数组实现的字符串的数组——二维数组 用指针实现的字符串数组——指针数组 注意 字符串和指针有着紧密的联系&#…

力扣(105. 从前序与中序遍历序列构造二叉树,106. 从中序与后序遍历序列构造二叉树)

题目1链接 题目1&#xff1a; 思路&#xff1a;使用前序确定根&#xff0c;使用中序分左右子树&#xff0c;分治法。 难点&#xff1a;如何控制递归确定左右子树。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* T…

【STM32】FLASH闪存

1 FLASH闪存简介 本节所指STM32内部闪存&#xff0c;即下载程序的时候&#xff0c;程序存储的地方。&#xff08;非易失性&#xff09; STM32F1系列的FLASH包含程序存储器、系统存储器&#xff08;bootloader&#xff0c;不允许修改&#xff09;和选项字节三个部分&#xff0…

华西建筑智能化寻找志同道合的创业团队

我今天四十多了&#xff0c;之前也创过业&#xff0c;做软件开发系统集成的。 19年进入华西建筑装饰工程有限公司负责机电安装及弱电智能化版块。后公司成立建筑智能化事业部&#xff0c;我负责。现在想全身心打造施工企业项目管理平台&#xff0c;同时进军智慧康养领域。我想…

1.5矩阵元素的引用

通过下标来引用矩阵的元素 A(3, 2)表示A矩阵第3行第2列的元素。 >> arr [1,2,3;4,5,6]; >> arr(4, 5) 10arr 1 2 3 0 04 5 6 0 00 0 0 0 00 0 0 0 10>> 如果引用元素超过矩阵的大小将自…

Windows下面基于pgsql15的备份和恢复

一、基础备份 1.创建一个文件用来存储备份数据 2.备份指令 $CurrentDate Get-Date -Format "yyyy-MM-dd" $OutputDirectory "D:\PgsqData\pg_base\$CurrentDate" $Command "./pg_basebackup -h 127.0.0.1 -U postgres -Ft -Pv -Xf -z -Z5 -D $O…

Navicat 16 for MySQL:打造高效数据库开发管理工具

随着数据的快速增长和复杂性的提升&#xff0c;数据库成为了现代应用开发中不可或缺的一部分。而在MySQL数据库领域&#xff0c;Navicat 16 for MySQL作为一款强大的数据库开发管理工具&#xff0c;正受到越来越多开发者的青睐。 Navicat 16 for MySQL拥有丰富的功能和直观的界…

功能权限篇

文章目录 1. 如何设计一套权限系统1.1 目标1.2 权限模型1.2.1 模型一RBAC1.2.2 模型二ABAC 2.如何实现菜单的创建&#xff1f;2.1 表结构2.2 前端实现2.3 后端实现 3. 如何实现角色的创建&#xff1f;4.如何给用户分配权限 —— 将菜单赋予角色&#xff1f;5.如何给用户分配权限…

sqlilabs第五十三五十四关

Less-51(GET - GET - Error based - ORDER BY CLAUSE-String- Stacked injection) 手工注入 单引号闭合&#xff0c;和上一关一样堆叠注入解决 自动注入 和上一关一样 Less-52(GET - challenge - Union- 10 queries allowed -Variation 1) 手工注入 这一关开始后面的可以看…

设计模式之备忘录模式【行为型模式】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某…

QT上位机开发(函数运行时间分析)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 软件除了功能开发、debug之外&#xff0c;另外一个很重要的部分就是软件的优化和提高。这里面的优化&#xff0c;当然就是希望软件能够处理更多的数…

[Beego]1.Beego简介以及beego环境搭建,bee脚手架的使用,创建,运行项目

一.Beego介绍 Beego是一个开源的基于Golang的MVC框架&#xff0c;主要用于Golang Web开发,Beego可以用来快速开发API、Web、后端服务等各种应用。 Golang 的Web开发框架有很多,从 github star 数量来看Gin>Beego>lris>Echo>Revel>Buffalo 目前国内用的比较多的就…