最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

本文主要是介绍最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《最新SpringSecurity实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)》本章节介绍了如何通过SpringSecurity实现从配置自定义登录页面、表单登录处理逻辑的配置,并简单模拟...

前言

通过上一章节《最新Spring Security实战教程(一)初识Spring Security安全框架》的讲解介绍相信大家已经认识 Spring Security 安全框架,在我们创建第一个项目演示中,相信大家发现了默认表单登录的局限性
Spring Security 默认提供的登录页虽然快速可用,但存在三大问题:

  • 界面风格与业务系统不匹配
  • 登录成功/失败处理逻辑固定
  • 缺乏扩展能力(如验证码、多因子认证)

本章节我们将Spring Security 默认表单进行登录定制到处理逻辑的深度改造

改造准备

现在在之前的Maven项目中创建第二个子模块,命名 login-spring-secutity ,由于我们需要自定义登陆页,还需要追加引入 thymeleaf 模版框架

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

完整的maven项目结构如下:

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

开始登录页改造

我们第一步需要自定义自己的带验证码的登陆页,在 resources/templates 目录下创建login.html

<!-- src/main/resources/templates/login.html -->
<!DOCTYPE html>
<html XMLns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>企业级登录系统</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >
</head>
<body>
<div class="container d-Flex justify-content-center align-items-center vh-100">
    <div class="w-100">
        <div class="card">
            <div class="card-body">
                <h2 class="card-title text-center mb-4">登录</h2>
                <form th:action="@{/login}" method="post">
                    <div class="mb-3">
                        <label for="username" class="form-label">用户名</label>
                        <input type="text" class="form-control" name="username" id="username" placeholder="请输入用户名">
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">密码</label>
                        <input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
                    </div>
                    <div class="d-grid gap-2">
                        <button type="submit" class="btn btn-primary">登录</button>
                    </div>
                    <p class="mt-3 text-center"><a href="#" rel="external nofollow"  rel="external nofollow" >忘记密码?</a></p>
                </form>
            </div>
        </div>
    </div>
</div>
</body>
</html>

添加一个默认首页index.html,显示登出按钮

<!-- src/main/resources/templates/index.html -->
<html xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>企业级登录系统</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="external no编程follow"  rel="external nofollow"  rel="external nofollow" >
</head>
<body>
<h1>Hello Security</h1>
<!-- 测试过程不需要关闭csrf防护 -->
<form th:action="@{/login}" method="post">
    <button type="submit" class="btn btn-primary">Log Out</button>
</form>
<!-- 测试过程需要关闭csrf防护 否则404 -->
<a th:href="@{/logout}" rel="external nofollow" >Log Out</a>
</body>
</html>

添加 contrller 配置首页以及登陆页

@Controller
public class DemoTowController {
    @GetMapping("/login")
    public String login() {
        return "login";
    }
    @GetMapping("/")
    public String index() {
        return "index";
    }
}

最后对 Spring Security 进行配置

@Configuration
public class BasicSecurityConfig {
    // 配置安全策略
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.
                authorizeHttpRequests(authorize -> authorize
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login") // 自定义登录页路径
                        .permitAll() //不需要对login认证
                )
                .logout(withDefaults())
                .csrf(csrf -> csrf.disable()) //关闭csrf防护
        ;
        return http.build();
    }
}

测试访问默认访问主页,由于主页被拦截会自动跳转自login登陆页

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

输入正确用户名密码后,自动返回主页,点击登出按钮自动回到登录页

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

特别说明:

注意登录页以及主页登出,action 采用 @{} 生成URL,Spring Security会自动帮我们生成name为_csrf 的隐藏表单,作用于 csrf 防护

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

如果你登出页是 a 连接形式,为了保证登出不会404的问题
1、我们先关闭 csrf 防护 http.csrf(csrf -> csrf.disable())
2、登出按钮使用表单方式 th:action="@{/logout}"

自定义用户名密码

到这里有小伙伴又要说了,每次密码都是Spring Security自动生成的UUID,能自定义用户名密码,答案是肯定的。Spring Security提供了在Spring Boot配置文件设置用户密码功能

# 默认安全配置(可通过application.yml覆盖)
spring:
  security:
    user:
      name: admin
      password: admin

登陆成功失败跳转问题

通过上述代码,小伙伴们看到登陆成功后,默认返回系统主页 即:index.html页面,因为业务需求需要跳转到别的页面,如何配置?

Spring Security 配置类中 formLogin 提供了两个参数 defaultSuccessUrlfailureUrl 方便我们进行配置

http.formLogin(form -> form
    .loginPage("/login") // 自定义登录页路径
    .defaultSuccessUrl("/home", true) // 登录成功后跳转路径
    .failureUrl("/login?error=true")  // 登录失败后跳转路径
    .permitAll() //不需要对login认证
)

自定义登出

登出和登录基本相同,由于篇幅问题这里博主就不配置登出的页面以及登出成功页面了,主要看以下配置,相信大家都能理解了

http.logout(logout -> logout
    .logoutUrl("/logout") //自定义登出页
    .logoutSuccessUrl("/login?logout") //登出成功跳转
)

前后端分离适配方案

上述的案例中针对的是前后端都在一个整体中的情况,针对现在前后端分离的项目我们如何来进行改造?我们处理以下问题:

  • 用户登陆成功返回登陆成功 / 失败 返回对应jsON
  • 用户登出成功返回登出成功 / 失败 返回对应JSON

这里博主首先引入官方的一个介绍图,如下:
我们发现在身份认证管理器 AuthenticationManager中, 有两个结果 Success 以及 Failure ,最终交给android AuthenticationSuccessHandler 以及 AuthenticationFailureHandler 处理器处理。

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

简单总结:

  • 登录成功调用:AuthenticationSuccessHandler
  • 登录失败调用:AuthenticationFailureHandler

通过上面的讲解,我们只需要自定义这两个处理器即可,我们在配置文件中增加这两个处理器,完整代码如下:

 // 自定义登录成功处理器
@Configuration
public class BasicSecurityConfig {
    // 配置安全策略
    @Bean
    public SecurityFilterChain filterChain(Ht编程tpSecurity http) throws Exception {
        http.
                authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/AJAXLogin").permitAll() //ajax登陆页不需要认证
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login") // 自定义登录页路径
//                        .defaultSuccessUrl("/", true)        // 登录成功后跳转路径
//                        .failureUrl("/login?error=true")         // 登录失败后跳转路径
                        .successHandler(loginSuccessHandler())
                        .failureHandler(loginFailureHandler())
                        .permitAll() //不需要对login认证
                )
                .logout(withDefaults())
                .csrf(csrf -> csrf.disable()) //关闭csrf防护
        ;
        return http.build();
    }
    // 自定义登录成功处理器
    @Bean
    public AuthenticationSuccessHandler loginSuccessHandler() {
        return (request, response, authentication) -> {
            if (isAjaxRequest(request)) {
                response.setContentType("application/json");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("{\"code\":200, \"message\":\"/认证成功\"}");
            } else {
                response.sendRedirect("/");
            }
        };
    }
    // 自定义登录失败处理器
    @Bean
    public AuthenticationFailureHandler loginFailureHandler() {
        return (request, response, exception) -> {
            if (isAjaxRequest(request)) {
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("{\"code\":401, \"message\":\"认证失败\"}");
            } else {
                response.sendRedirect(China编程"/login?error=true");
            }
        };
    }
    //判断是否ajax请求
    public boolean isAjaxRequest(HttpServletRequest request) {
        String xRequestedwith = request.getHeader("X-Requested-With");
        return "XMLHttpRequest".equals(xRequestedWith);
    }

最后新增一个ajaxLogin.html 使用ajax发送请求(为了测试方便这里就简单创建一个,不使用vue等工程了

<!-- src/main/resources/templates/ajaxLogin.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>企业级登录系统</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<div class="container d-flex justify-content-center align-items-center vh-100">
    <div class="w-100">
        <div class="card">
            <div class="card-body">
                <h2 class="card-title text-center mb-4">登录</h2>
                <form>
                    <div class="mb-3">
                        <label for="username" class="form-label">用户名</label>
                        <input type="text" class="form-control" name="username" id="username" placeholder="请输入用户名">
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">密码</label>
                        <input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
                    </div>
                    <div class="d-grid gap-2">
                        <button type="submit" class="btn btn-primary">登录</button>
                    </div>
                    <p class="mt-3 text-center"><a href="#" rel="external nofollow"  rel="external nofollow" >忘记密码?</a></p>
                </form>
            </div>
        </div>
    </div>
</div>
<script>
    $(document).ready(function () {
        $('form').submit(function (event) {
            event.preventDefault();
            var username = $('#username').val();
            var password = $('#password').val();
            $.ajax({
                type: 'POST',
                url: '/login',
                data: {
                    username: username,
                    password: password
                },
                success: function (response) {
                    console.log(response)
                    if(response.code ==200){
                        window.location.href = '/';
                    }
                }
            })
        })
    })
</script>
</body>
</html>

controller 中追加页面展示

@GetMapping("/ajaxLogin")
    public String ajaxLogin() {
        return "ajaxLo编程China编程gin";
}

最后启动Spring Boot项目,访问 /ajaxLogin 登陆页,测试输入正确和不正确的账号密码进行测试,并观察浏览器控制台输出

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

结语

本章节介绍了如何通过Spring Security实现从配置自定义登录页面、表单登录处理逻辑的配置,并简单模拟了前后分离的适配方案。小伙伴们可以跟着博主的样例代码自己敲一遍进行相关测试!如果本本章内容对您有所帮助,希望 一键三连 给博主一点点鼓励,如果您有任何疑问或建议,请随时留言讨论!

在接下来的章节中,我们将逐步深入 Spring Security 的各个技术细节,带你从入门到精通,全面掌握这一安全技术的方方面面。欢迎继续关注!

到此这篇关于最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)的文章就介绍到这了,更多相关Spring Security表单登录内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153839

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Java中的工具类命名方法

《Java中的工具类命名方法》:本文主要介绍Java中的工具类究竟如何命名,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java中的工具类究竟如何命名?先来几个例子几种命名方式的比较到底如何命名 ?总结Java中的工具类究竟如何命名?先来几个例子JD

Java Stream流使用案例深入详解

《JavaStream流使用案例深入详解》:本文主要介绍JavaStream流使用案例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录前言1. Lambda1.1 语法1.2 没参数只有一条语句或者多条语句1.3 一个参数只有一条语句或者多