SpringBoot集成Spring Security(7)——認證流程


文章目錄

  • 一、認證流程
  • 二、多個請求共享認證信息
  • 三、獲取用戶認證信息
在前面的六章中,介紹了 Spring Security 的基礎使用,在繼續深入向下的學習前,有必要理解清楚 Spring Security 的認證流程,這樣才能理解為什么要這樣寫代碼,也方便后續的擴展。

 

一、認證流程

上圖是 Spring Security 認證流程的一部分,下面的講解以上圖為依據。

 

(1) 用戶發起表單登錄請求后,首先進入 UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter 中根據用戶輸入的用戶名、密碼構建了 UsernamePasswordAuthenticationToken,並將其交給 AuthenticationManager 來進行認證處理。

AuthenticationManager 本身不包含認證邏輯,其核心是用來管理所有的 AuthenticationProvider,通過交由合適的 AuthenticationProvider 來實現認證。

(2) 下面跳轉到了 ProviderManager ,該類是 AuthenticationManager 的實現類:

我們知道不同的登錄邏輯它的認證方式是不一樣的,比如我們表單登錄需要認證用戶名和密碼,但是當我們使用三方登錄時就不需要驗證密碼。

Spring Security 支持多種認證邏輯,每一種認證邏輯的認證方式其實就是一種 AuthenticationProvider。通過 getProviders() 方法就能獲取所有的 AuthenticationProvider,通過 provider.supports() 來判斷 provider 是否支持當前的認證邏輯。

當選擇好一個合適的 AuthenticationProvider 后,通過 provider.authenticate(authentication) 來讓 AuthenticationProvider 進行認證。

(3) 傳統表單登錄的 AuthenticationProvider 主要是由 AbstractUserDetailsAuthenticationProvider 來進行處理的,我們來看下它的 authenticate()方法。

首先通過 retrieveUser() 方法讀取到數據庫中的用戶信息:

user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);

retrieveUser() 的具體實現在 DaoAuthenticationProvider 中,代碼如下:

當我們成功的讀取 UserDetails 后,下面開始對其進行認證:

在上圖中,我們可以看到認證校驗分為 前校驗、附加校驗和后校驗,如果任何一個校驗出錯,就會拋出相應的異常。所有校驗都通過后,調用 createSuccessAuthentication() 返回認證信息。

在 createSuccessAuthentication 方法中,我們發現它重新 new 了一個 UsernamePasswordAuthenticationToken,因為到這里認證已經通過了,所以將 authorities 注入進去,並設置 authenticated 為 true,即需要認證。

(4)至此認證信息就被傳遞回 UsernamePasswordAuthenticationFilter 中,在 UsernamePasswordAuthenticationFilter 的父類 AbstractAuthenticationProcessingFilterdoFilter() 中,會根據認證的成功或者失敗調用相應的 handler:

這里調用的 handler 實際就是在《SpringBoot集成Spring Security(6)——登錄管理》中我們在配置文件中配置的 successHandler() 和 failureHandler()

二、多個請求共享認證信息

Spring Security 通過 Session 來保存用戶的認證信息,那么 Spring Security 到底是在什么時候將認證信息放入 Session,又在什么時候將認證信息從 Session 中取出來的呢?

下面將 Spring Security 的認證流程補充完整,如下圖:

在上一節認證成功的 successfulAuthentication()方法中,有一行語句:

其實就是在這里將認證信息放入 Session 中。

查看 SecurityContext 源碼,發現內部就是對 Authentication 的封裝,提供了 equals、hashcode、toString等方法,而SecurityContextHolder 可以理解為線程中的 ThreadLocal

我們知道一個 HTTP 請求和響應都是在一個線程中執行,因此在整個處理的任何一個方法中都可以通過 SecurityContextHolder.getContext()來取得存放進去的認證信息。

從 Session 中對認證信息的處理由 SecurityContextPersistenceFilter 來處理,它位於 Spring Security 過濾器鏈的最前面,它的主要作用是:

  • 當請求時,檢查 Session 中是否存在 SecurityContext,如果有將其放入到線程中。
  • 當響應時,檢查線程中是否存在 SecurityContext,如果有將其放入到 Session 中。

三、獲取用戶認證信息

通過調用 SecurityContextHolder.getContext().getAuthentication() 就能夠取得認證信息:

@GetMapping("/me")
@ResponseBody
public Object me() {
    return SecurityContextHolder.getContext().getAuthentication();
}

 

上面的寫法有點啰嗦,我們可以簡寫成下面這種, Spring MVC 會自動幫我們從 Spring Security 中注入:

@GetMapping("/me")
@ResponseBody
public Object me(Authentication authentication) {
    return authentication;
}

如果你僅想獲取 UserDetails 對象,也是可以的,寫法如下:

 

 


---------------------
作者:Jitwxs
來源:CSDN
原文:https://blog.csdn.net/yuanlaijike/article/details/84703690


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM