- 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.tw/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,您可以看到登入頁面。
輸入無效憑據
錯誤頁面
如果我們輸入無效憑據,則使用者將被重定向到錯誤頁面。