1. 概述
本快速教程將演示如何在 Spring Boot 應用程序中自定義 Spring Security 的身份驗證失敗處理。目標是使用一種 表單登錄 方式進行用户身份驗證。
對於 Spring Security 和 表單登錄 在 Spring Boot 中的介紹,請參閲相應文章:[此處鏈接] 和 [此處鏈接]。
2. 身份驗證與授權
身份驗證(Authentication)和授權(Authorization)經常一起使用,因為它們在授予系統訪問權限時起着至關重要且同樣重要的作用。
然而,它們具有不同的含義,並在驗證請求時應用不同的約束條件:
- 身份驗證——在授權之前進行;它涉及驗證收到的憑據;即,我們驗證用户名和密碼是否與應用程序所認識的憑據匹配
- 授權——它涉及驗證已成功身份驗證的用户是否具有訪問應用程序特定功能的權限
我們可以自定義身份驗證和授權失敗處理,但是,在本應用程序中,我們將重點關注身份驗證失敗處理。
3. Spring Security 的 <em >AuthenticationFailureHandler</em >
Spring Security 提供了一個默認組件,用於處理身份驗證失敗。
然而,我們經常會遇到默認行為無法滿足需求的情況。
如果是這樣, 我們可以創建自己的組件並通過實現 AuthenticationFailureHandler 接口,來提供我們需要的自定義行為。
public class CustomAuthenticationFailureHandler
implements AuthenticationFailureHandler {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
Map<String, Object> data = new HashMap<>();
data.put(
"timestamp",
Calendar.getInstance().getTime());
data.put(
"exception",
exception.getMessage());
response.getOutputStream()
.println(objectMapper.writeValueAsString(data));
}
}默認情況下,Spring 會將用户重定向回登錄頁面,並通過包含錯誤信息的請求參數進行傳遞。
在本應用程序中,我們將返回一個 401 響應,其中包含錯誤信息的詳細信息以及發生時間戳。
除了默認組件之外,Spring 還提供了其他可用的組件,我們可以根據需要進行利用:
- DelegatingAuthenticationFailureHandler 將AuthenticationException 子類委託給不同的AuthenticationFailureHandlers,這意味着我們可以為不同的 AuthenticationException 實例創建不同的行為。
- ExceptionMappingAuthenticationFailureHandler 根據 AuthenticationException 的完整類名,將用户重定向到特定的 URL。
- ForwardAuthenticationFailureHandler 無論 AuthenticationException 的類型如何,都將用户轉發到指定的 URL。
- SimpleUrlAuthenticationFailureHandler 是默認使用的組件,如果指定了 failureUrl,則將用户重定向到該 URL;否則,它將簡單地返回一個 401 響應。
現在我們已經創建了自定義 AuthenticationFailureHandler,讓我們配置應用程序並覆蓋 Spring 的默認處理程序:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user1 = User.withUsername("user1")
.password(passwordEncoder().encode("user1Pass"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user1);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.failureHandler(authenticationFailureHandler())
return http.build();
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}請注意failureHandler() 調用——這是我們告訴 Spring 使用我們自定義組件而不是使用默認組件的地方。
4. 結論
在本示例中,我們通過利用 Spring 的 AuthenticationFailureHandler 接口,自定義了應用程序的身份驗證失敗處理程序。
當本地運行應用程序時,您可以通過訪問 localhost:8080 進行訪問和測試。