Spring Security添加验证码的两种方式小结

下面详细讲解如何给Spring Security添加验证码的两种方式:

方式1:自定义验证码过滤器

  1. 首先创建一个实现javax.servlet.Filter接口的验证码过滤器类VerifyCodeFilter,并在其中生成并输出验证码图片。示例代码:
public class VerifyCodeFilter extends OncePerRequestFilter {

    private static final String SESSION_KEY_VERIFY_CODE = "SESSION_KEY_VERIFY_CODE";

    private static final String REQUEST_PARAMETER_VERIFY_CODE = "verifyCode";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if ("/login".equals(request.getRequestURI()) && "POST".equalsIgnoreCase(request.getMethod())) {
            try {
                validate(request);
            } catch (VerifyCodeException e) {
                request.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION", e);
                request.getRequestDispatcher("/login?error").forward(request, response);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

    private void validate(HttpServletRequest request) throws VerifyCodeException {
        String sessionVerifyCode = getSessionVerifyCode(request);
        String requestVerifyCode = getParameterVerifyCode(request);
        if (StringUtils.isBlank(requestVerifyCode) || !sessionVerifyCode.equalsIgnoreCase(requestVerifyCode)) {
            throw new VerifyCodeException("验证码不匹配");
        }
    }

    private String getSessionVerifyCode(HttpServletRequest request) {
        HttpSession session = request.getSession();
        return session.getAttribute(SESSION_KEY_VERIFY_CODE).toString();
    }

    private String getParameterVerifyCode(HttpServletRequest request) {
        return request.getParameter(REQUEST_PARAMETER_VERIFY_CODE);
    }

    private void setSessionVerifyCode(HttpServletRequest request, String verifyCode) {
        HttpSession session = request.getSession();
        session.setAttribute(SESSION_KEY_VERIFY_CODE, verifyCode);
    }

    private void outputImage(HttpServletRequest request, HttpServletResponse response, BufferedImage image) throws IOException {
        response.setContentType("image/png");
        OutputStream out = response.getOutputStream();
        ImageIO.write(image, "png", out);
        out.flush();
        out.close();
    }

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if ("/login".equals(request.getRequestURI()) && "GET".equalsIgnoreCase(request.getMethod())) {
            String verifyCode = verifyCodeGenerator();
            setSessionVerifyCode(request, verifyCode);
            BufferedImage bufferedImage = generateVerifyCodeImage(verifyCode);
            outputImage(request, response, bufferedImage);
            return;
        }
        filterChain.doFilter(request, response);
    }

    private String verifyCodeGenerator() {
        Random random = new Random();
        int bound = 999999;
        int verifyCode = random.nextInt(bound);
        return String.format("%06d", verifyCode);
    }

    private BufferedImage generateVerifyCodeImage(String verifyCode) {
        // 绘制验证码图片的逻辑
        return null;
    }

}
  1. 然后,将验证码过滤器添加到Spring Security的过滤器链中。在Spring Security的配置类上添加如下代码:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            ...
    }

    ...
}
  1. 最后,在登录页面的表单中添加验证码输入框,和一个获取验证码图片的链接。示例代码:
<form th:action="@{/login}" method="post">
    <div>
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required autofocus>
    </div>
    <div>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password" required>
    </div>
    <div>
        <label for="verify-code">Verify Code:</label>
        <input type="text" id="verify-code" name="verifyCode" required>
    </div>
    <div>
        <a th:href="@{/verifyCode}" target="_blank">Get Verify Code</a>
    </div>
    <div>
        <button type="submit">Log in</button>
    </div>
</form>

方式2:使用Spring Security官方提供的验证码验证功能

  1. 首先,在Spring Security的配置类中添加如下配置类,以开启验证码功能:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                ...
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/authenticate")
                .failureUrl("/login?error")
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .permitAll()
                .and()
                .csrf()
                .disable()
                .apply(new SmsCodeAuthenticationSecurityConfig())
                .apply(new VerifyCodeSecurityConfig()) // 添加验证码功能
                .apply(new SocialAuthenticationConfig())
                .apply(new RememberMeConfig());
    }

}
  1. 接下来,自定义一个实现org.springframework.security.web.authentication.AuthenticationSuccessHandler接口的类MyAuthenticationSuccessHandler,用于在登录成功之后,将验证码删除。示例代码:
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final VerificationCodeRepository verificationCodeRepository;

    public MyAuthenticationSuccessHandler(VerificationCodeRepository verificationCodeRepository) {
        this.verificationCodeRepository = verificationCodeRepository;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        String mobile = request.getParameter("mobile");
        verificationCodeRepository.remove(mobile, "LOGIN");
        response.sendRedirect("/");
    }
}
  1. 最后,在登录页面的表单中添加验证码输入框、隐藏域,并在Spring Security的配置类中指定如下配置:
<form th:action="@{/authenticate}" method="post">
    ...
    <div>
        <label for="verify-code">Verify Code:</label>
        <input type="text" id="verify-code" name="verifyCode" required>
        <input type="hidden" name="uuid" th:value="${uuid}">
    </div>
    ...
</form>
@Configuration
public class VerifyCodeSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 先将验证码过滤器添加到spring security过滤器链
        VerifyCodeFilter verifyCodeFilter = new VerifyCodeFilter();
        http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);

        // 配置验证码认证通过失败的处理器
        VerifyCodeFilterResultHandler verifyCodeFilterResultHandler = new VerifyCodeFilterResultHandler(verifyCodeFilter);
        http.exceptionHandling()
                .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
                .accessDeniedHandler(new AccessDeniedHandlerImpl())
                .and()
                .formLogin()
                .successHandler(new MyAuthenticationSuccessHandler(verificationCodeRepository())) // 设置登录成功处理器,在登录成功的时候删除验证码
                .failureHandler(verifyCodeFilterResultHandler) // 登录失败也返回头部信息,其中可能会包含uuid参数
                .and()
                .addFilterBefore(new VerifyCodePersistenceFilter(verificationCodeRepository()), UsernamePasswordAuthenticationFilter.class) // 持久化uuid和验证码的过滤器,搭配在 LoginWithUuidAuthenticationProvider 一起对通过验证码登陆的用户进行认证
                .authenticationProvider(new LoginWithUuidAuthenticationProvider(verificationCodeRepository(), userDetailsService())) // 配置自定义 AuthenticationProvider
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .permitAll()
                .and()
                .csrf()
                .disable();
    }

}

以上就是向Spring Security中添加验证码的两种方式,你可以根据具体需求选择适合自己的方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security添加验证码的两种方式小结 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • 详解maven的install的作用

    下面我来详细讲解一下“详解maven的install的作用”的完整攻略。 什么是 Maven Maven 是一个基于项目对象模型(POM)、依赖管理、构建生命周期和插件化架构的项目管理工具。通过Maven的POM文件,可以管理项目的依赖、生命周期、构建、测试等各个环节。 Maven Install 在 Maven 中,install 是指安装构建的文件到本地…

    Java 2023年5月20日
    00
  • SpringBoot项目使用aop案例详解

    下面我为大家详细讲解“SpringBoot项目使用aop案例详解”的完整攻略。 一、什么是AOP AOP(Aspect Oriented Programming),即面向切面编程,是一种编程思想,它的原理就是在不改变原有代码结构的基础上,对横切关注点进行描述,便于将这些非功能性的需求模块化,降低系统耦合度。在Spring Framework中,AOP通过切面…

    Java 2023年5月31日
    00
  • SpringMVC实现多文件上传

    以下是关于“SpringMVC实现多文件上传”的完整攻略,其中包含两个示例。 SpringMVC实现多文件上传 在SpringMVC中,我们可以通过MultipartFile类来实现多文件上传。在本文中,我们将讲解如何使用MultipartFile类来实现多文件上传。 多文件上传实现原理 SpringMVC通过使用MultipartFile类来实现多文件上传…

    Java 2023年5月17日
    00
  • Nginx 连接tomcat时会话粘性问题分析及解决方法

    Nginx 连接tomcat时会话粘性问题分析及解决方法 问题背景 在使用 Nginx 对 Tomcat 进行反向代理时,如果不做任何特殊处理,有可能出现会话粘性问题,即同一个用户的请求被转发到了不同的 Tomcat 实例上,导致会话信息丢失,从而导致用户操作失败。 问题分析 会话粘性问题的根本原因是访问服务器时没有考虑到会话信息,导致同一用户的请求在多个服…

    Java 2023年6月16日
    00
  • 猜你不知道Spring Boot的几种部署方式(小结)

    下面将为您详细介绍“猜你不知道SpringBoot的几种部署方式(小结)”这篇文章的完整攻略。 简介 在这篇文章中,我们将会介绍SpringBoot的几种部署方式,包括: 傻瓜式部署 War包部署 Jar包部署 我们将详细讲解每种部署方式的具体实现步骤以及使用场景,帮助读者更好地理解和应用SpringBoot的部署方式。 傻瓜式部署 傻瓜式部署是最简单的一种…

    Java 2023年5月15日
    00
  • Java TimedCache 带时间缓存工具类详解使用

    Java TimedCache 带时间缓存工具类详解使用 Java TimedCache 是一个开源的缓存工具类,能够实现基于时间的缓存。该工具类非常适用于需要经常访问、变化较少的数据,例如数据库或文件系统中的静态数据。下面是使用 Java TimedCache 的详细攻略。 1. 下载和导入 TimedCache 类库 可以从 GitHub 或 Maven…

    Java 2023年5月20日
    00
  • unicode utf-8 gb18030 gb2312 gbk各种编码对比

    Unicode、UTF-8、GB2312、GBK和GB18030都是用于将文本数据编码成二进制数据进行传输和存储的标准。 Unicode Unicode是一种贯穿始终的字符集标准,它在不同的编码方式下可以翻译成不同的二进制数据。Unicode对于所有的文字都有唯一的编码,包括英文、中文、拉丁文、凯尔特文等等世界上所有的文字。Unicode 编码是一种固定的编…

    Java 2023年5月20日
    00
  • SpringBoot浅析安全管理之高级配置

    Spring Boot浅析安全管理之高级配置 Spring Boot提供了强大的安全管理功能,可以帮助开发人员保护应用程序的安全性。在本文中,我们将深入探讨Spring Boot安全管理的高级配置。 Spring Boot安全管理的基本概念 在Spring Boot中,安全管理是指保护应用程序的机制,以确保只有授权用户才能访问应用程序的资源。Spring B…

    Java 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部