Springboot +spring security,自定义认证器实现验证码功能

news/2025/2/12 23:19:34/

一.简介

SpringSecurity 默认是不支持验证码功能的,但是可以自己扩展,这也是使用SpringSecurity的好处之一,原生不支持,我们就自己扩展。

二.思路分析

因为系统默认的有一个DaoAuthenticationProvider 认证处理器,但是他只支持用户名和密码方式登录,所以是不能使用现有的认证器,那我们是不是可以实现一个自己的认证器,来覆盖这个默认的认证器呢?答案当然是可以的,大概实现思路是这样的:

  1. 创建一个认证器 继承默认的密码认证器DaoAuthenticationProvider
  2. 定义验证码认证器的逻辑
    2.1. 从session获取保存的验证码
    2.2. 从请求参数中获取用户输入的验证码
    2.3. 比对验证码
    2.4. 如果匹配成功,则调用DaoAuthenticationProvider的authenticate方法,进行原先逻辑认证
    2.5. 如果匹配失败,则抛出异常,不走后面的逻辑
  3. 将自定义的provider加到AuthenticationManager中

这篇文章来看下如何通过自定义认证器来实现验证码校验的功能。

三.创建项目

如何创建一个SpringSecurity项目,前面文章已经有说明了,这里就不重复写了。

四.代码实现

4.1创建验证码处理器

4.1.1引入依赖

验证码的依赖:

com.github.penggle:kaptcha:2.3.2

4.1.2配置验证码

配置验证码的代码如下:

@Beanpublic Producer producer() {Properties properties = new Properties();properties.setProperty("kaptcha.image.width", "150");properties.setProperty("kaptcha.image.height", "50");properties.setProperty("kaptcha.textproducer.char.string", "012");properties.setProperty("kaptcha.textproducer.char.length", "4");Config config = new Config(properties);DefaultKaptcha defaultKaptcha = new DefaultKaptcha();defaultKaptcha.setConfig(config);return defaultKaptcha;}

4.1.3创建验证码入口

创建验证码入口的代码如下:

@Autowired(required = false)private Producer producer;@RequestMapping("/kaptcha")public void kaptcha(HttpServletResponse response, HttpSession session){response.setContentType("image/jpg");String text = producer.createText();session.setAttribute("KAPTCHA_CODE",text);BufferedImage image = producer.createImage(text);try(ServletOutputStream outputStream = response.getOutputStream()){ImageIO.write(image,"jpg",outputStream);} catch (IOException e) {throw new RuntimeException(e);}}

4.2自定义验证码认证处理器

自定义验证码认证处理器代码如下:

public class KaptchaAuthenticationProvider extends DaoAuthenticationProvider {@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();String kaptchaCode = (String) request.getSession().getAttribute("KAPTCHA_CODE");String inputKaptcha = request.getParameter("kaptcha");if (!StrUtil.equals(kaptchaCode, inputKaptcha)) {throw new InternalAuthenticationServiceException("验证码验证失败");}return super.authenticate(authentication);}
}

4.3自定义登录页面

自定义登录页面的前端代码如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div th:text="${SPRING_SECURITY_LAST_EXCEPTION}"></div>
<form action="/login" method="post">用户名:<input name="username" type="text"><br>密码:<input name="password" type="password"><br>验证码:<input name="kaptcha" type="text"><br><img src="/kaptcha"><button type="submit">登陆</button>
</form>
</body>
</html>

4.4配置SecurityFilterchain

配置SecurityFilterchain的代码如下:

@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((auth) ->{try {auth.antMatchers("/kaptcha").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/login").failureForwardUrl("/login.html").permitAll().and().csrf().disable();}catch (Exception e){}});return http.build();}

4.5配置AuthenticationManager

配置AuthenticationManager的代码如下:

@Beanpublic UserDetailsService userDetailsService(){UserDetails userDetails = User.withUsername("memory1").password("{noop}memory1").roles("memory1").build();return new InMemoryUserDetailsManager(userDetails);}@Beanpublic KaptchaAuthenticationProvider kaptchaAuthenticationProvider(){KaptchaAuthenticationProvider kaptchaAuthenticationProvider= new KaptchaAuthenticationProvider();kaptchaAuthenticationProvider.setUserDetailsService(userDetailsService());return kaptchaAuthenticationProvider;}@Beanpublic AuthenticationManager authenticationManager(){return new ProviderManager(kaptchaAuthenticationProvider());}

五.验证登录

截图如下:
在这里插入图片描述
在这里插入图片描述
至此,扩展验证码功能就处理好了。


http://www.ppmy.cn/news/74026.html

相关文章

使用Python实现Rest API指南

在今天的数字化世界中&#xff0c;数据的获取、交换和使用已经成为几乎所有行业的核心部分。无论您正在为一个大型公司设计复杂的软件系统&#xff0c;还是只是为了个人项目尝试获得一些公开的数据&#xff0c;理解和利 用API——尤其是RESTful API——都是一项至关重要的技术。…

细说java动态代理及使用场景

一、定义 Java代理模式是一种结构型设计模式&#xff0c;它允许通过创建一个代理对象来间接访问另一个对象&#xff0c;从而控制对原始对象的访问。 1.1 作用 1、在访问原始对象时增加额外功能&#xff0c;如访问前或访问后添加一些额外的行为。 2、控制对原始对象的访问。 J…

ARM汇编 C语言数据存储 堆和栈的区别

ARM汇编 ARM汇编是一种用于编写针对ARM架构的汇编语言。它是ARM处理器的底层指令集的人类可读表示形式&#xff0c;用于编写底层的系统级代码或优化特定的程序。 ARM汇编语言使用助记符&#xff08;mnemonic&#xff09;来表示不同的指令操作&#xff0c;例如"ADD&quo…

apk 作为资源提供 aar 的过程

1&#xff1a;参考&#xff1a;Android将APK项目封装为SDK(AAR) https://blog.csdn.net/weixin_51522235/article/details/128216091 四大点&#xff1a;1: apply plugin:com.android.library 2:去掉&#xff1a;applicationId 3:去掉&#xff1a;applicationVariants.all…

keycloak异常关闭报错username ‘admin‘ already added时卡死无法重启的问题处理

问题现象 使用docker部署keycloak服务&#xff0c;使用docker-compose进行配置管理&#xff0c;配置如下&#xff1a; keycloak:image: jboss/keycloak:16.1.0 container_name: keycloakcommand:[-b,0.0.0.0,-Dkeycloak.migration.actionimport,-Dkeycloak.migration.provider…

深入理解 Linux 内核

Linux 内核系列文章 Linux 内核设计与实现 深入理解 Linux 内核 深入理解 Linux 内核&#xff08;二&#xff09; Linux 设备驱动程序 Linux设备驱动开发详解 文章目录 Linux 内核系列文章前言一、绪论二、内存寻址1、内存地址2、硬件中的分段&#xff08;1&#xff09;段选择符…

streamlit简介和使用教程2

文章目录 显示文本显示图像、视频音频进度和状态侧边栏和容器侧边栏容器显示图表显示文本 #显示文本 st.write("Hello,lets learn how to build a streamlit app together")st.title():用于添加应用程序的标题st.header():用于设置节的标题st.subheader():用于设…

深入分析实战可重入读写锁ReentrantReadWriteLock

文章目录 前言加锁规则同步原理源码解析实战演示 前言 前面我们学习了可重入锁ReentrantLock&#xff0c;可重入锁是一个排他锁&#xff0c;只要不是当前线程访问加锁资源都不能够进入&#xff0c;只能等待锁的释放。当然&#xff0c;这种加锁方式也有一定的适用场景。但是&am…