- Spring Security 教程
- Spring Security - 首页
- Spring Security - 简介
- Spring Security - 架构
- Spring Security - 项目模块
- Spring Security - 环境设置
- Spring Security - 表单登录
- Spring Security - 自定义表单登录
- Spring Security - 注销
- Spring Security - 记住我
- Spring Security - 重定向
- Spring Security - 标签库
- Spring Security - XML 配置
- Spring Security - 认证提供者
- Spring Security - 基本认证
- Spring Security - 认证失败处理器
- Spring Security - JWT
- Spring Security - 获取用户信息
- Spring Security - Maven
- Spring Security - 默认密码编码器
- Spring Security – 密码编码
- Spring Security - 方法级安全
- Spring Security 有用资源
- Spring Security - 快速指南
- Spring Security - 有用资源
- Spring Security - 讨论
Spring Security - 认证失败处理器
Spring Security 允许我们根据需要自定义我们的身份验证过程。从自定义登录页面到我们自己的自定义身份验证提供程序和身份验证过滤器,我们可以自定义身份验证过程的各个方面。我们可以定义我们自己的身份验证过程,该过程可以从使用用户名和密码的基本身份验证到使用令牌和 OTP 的复杂身份验证(如双因素身份验证)。我们还可以自定义身份验证失败处理。默认情况下,Spring Security 将用户重定向到登录页面,其中 HttpRequest 对象包含错误信息。
认证失败处理器
Spring Security 提供了 AuthenticationFailureHandler 接口,其中包含 onAuthenticationFailure() 方法。我们可以使用内置的处理器实现,也可以创建我们自己的处理器来自定义 onAuthenticationFailure() 方法的实现。
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.sendRedirect("/error");
}
}
这里,我们发送 http 状态 UNAUTHORIZED 或 401 并将用户重定向到错误页面。
AuthenticationFailureHandler 实现
Spring Security 提供了以下主要的 AuthenticationFailureHandler 实现。
SimpleUrlAuthenticationFailureHandler − 这是默认的身份验证失败处理器。如果指定了 failureUrl,则将其重定向到 failureUrl,否则返回 401 响应作为 UNAUTHORIZED。
ForwardAuthenticationFailureHandler − 此身份验证失败处理器将用户转发到提供的 URL。
ExceptionMappingAuthenticationFailureHandler − 此身份验证失败处理器根据 AuthenticationException 的名称将用户转发到提供的 URL。
DelegatingAuthenticationFailureHandler − 此身份验证失败处理器允许根据 AuthenticationException 实例使用其他 AuthenticationFailureHandler 实现。
我们将在接下来的部分创建我们自己的 AuthenticationFailureHandler。
Spring Security 配置
我们需要在 Spring Security 配置中配置 CustomAuthenticationFailureHandler。
http
//...
.formLogin(form -> form.loginPage("/login")
.defaultSuccessUrl("/")
.failureHandler(new CustomAuthenticationFailureHandler())
.permitAll())
...
}
这就是我们需要做的。现在让我们看看完整的代码。
在开始使用 Spring 框架编写第一个示例之前,您必须确保已正确设置 Spring 环境,如 Spring Security - 环境设置 章节中所述。我们还假设您对 Spring Tool Suite IDE 有基本的了解。
现在让我们继续编写一个由 Maven 管理的基于 Spring MVC 的应用程序,该应用程序将要求用户登录、对用户进行身份验证,然后使用 Spring Security 表单登录功能提供注销选项。
使用 Spring Initializr 创建项目
Spring Initializr 是开始 Spring Boot 项目的好方法。它提供了一个易于使用的用户界面来创建项目、添加依赖项、选择 Java 运行时等。它生成一个骨架项目结构,一旦下载,就可以导入到 Spring Tool Suite 中,然后我们可以继续使用我们的现成项目结构。
我们选择一个 Maven 项目,将项目命名为 formlogin,Java 版本为 21。添加以下依赖项:
Spring Web
Spring Security
Spring Boot DevTools
Thymeleaf 是一个用于 Java 的模板引擎。它允许我们快速开发静态或动态网页以在浏览器中呈现。它具有极强的可扩展性,允许我们详细定义和自定义模板的处理过程。此外,我们可以通过点击此 链接 了解更多关于 Thymeleaf 的信息。
让我们继续生成我们的项目并下载它。然后将其解压缩到我们选择的文件夹中,并使用任何 IDE 打开它。我将使用 Spring Tools Suite 4。它可以从 https://springframework.org.cn/tools 网站免费下载,并针对 Spring 应用程序进行了优化。
包含所有相关依赖项的 pom.xml
让我们看一下我们的 pom.xml 文件。它应该看起来类似于以下内容:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tutorialspoint.security</groupId>
<artifactId>formlogin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>formlogin</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
AuthenticationFailureHandler
在我们的 config 包中,我们通过实现 AuthenticationFailureHandler 接口创建了 CustomAuthenticationFailureHandler 类。在 onAuthenticationFailure() 方法中,我们将 HTTP 状态设置为 UNAUTHORIZED 并将用户重定向到错误页面。
package com.tutorialspoint.security.formlogin.config;
import java.io.IOException;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.sendRedirect("/error");
}
}
Spring Security 配置类
在我们的 config 包中,我们创建了 WebSecurityConfig 类。我们将使用此类进行安全配置,因此让我们使用 @Configuration 注解和 @EnableWebSecurity 注解它。这样,Spring Security 就会知道将此类视为一个配置类。正如我们所看到的,Spring 使配置应用程序变得非常容易。
WebSecurityConfig
package com.tutorialspoint.security.formlogin.config;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
protected UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(
request -> request.requestMatchers("/login").permitAll()
.requestMatchers("/error").permitAll()
.requestMatchers("/**").authenticated()
)
.formLogin(form -> form.loginPage("/login")
.defaultSuccessUrl("/")
.failureHandler(new CustomAuthenticationFailureHandler())
.permitAll())
.logout(config -> config
.logoutUrl("/logout")
.logoutSuccessUrl("/login"))
.build();
}
}
配置类详细信息
让我们看一下我们的配置类。
首先,我们将使用 userDetailsService() 方法创建 UserDetailsService 类的 bean。我们将使用此 bean 来管理此应用程序的用户。在这里,为了简单起见,我们将使用 InMemoryUserDetailsManager 实例来创建用户。这些用户以及我们给定的用户名和密码分别映射到 User 和 Admin 角色。
Http 安全配置
完成以上步骤后,我们继续进行下一个配置。在这里,我们定义了 filterChain 方法。此方法将 HttpSecurity 作为参数。我们将对其进行配置以使用我们的表单登录和注销功能。
我们可以看到所有这些功能都可以在 Spring Security 中使用。让我们详细研究以下部分:
return http
//...
.failureHandler(new CustomAuthenticationFailureHandler())
//...
.build();
这里我们添加了一个身份验证失败处理器作为 CustomAuthenticationFailureHandler 实例。
控制器类
在此类中,我们为单个 "/" 端点创建了一个映射,用于此应用程序的索引页面,以简单起见。这将重定向到 index.html。
AuthController
package com.tutorialspoint.security.formlogin.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AuthController {
@GetMapping("/")
public String home() {
return "index";
}
}
视图
在 /src/main/resources/templates 文件夹中创建 index.html,其内容如下,作为主页。
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head>
<title>
Hello World!
</title>
</head>
<body>
<h1 th:inline="text">Hello World!</h1>
<a href="/logout" alt="logout">Sign Out</a>
</body>
<html>
在 /src/main/resources/templates 文件夹中创建 error.html,其内容如下,作为错误页面。
error.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head>
<title>
Invalid Credentials
</title>
</head>
<body>
<h1>Invalid Credentials.</h1>
</body>
<html>
运行应用程序
由于我们已经准备好了所有组件,因此让我们运行应用程序。右键单击项目,选择 Run As,然后选择 Spring Boot App。
它将启动应用程序,并且应用程序启动后,我们可以运行 localhost:8080 来检查更改。
输出
现在打开 localhost:8080,您可以看到登录页面。
输入无效凭据
错误页面
如果我们输入无效凭据,则用户将被重定向到错误页面。