Spring Security 基本認證組件
1. 前言
在前面的章節(jié),我們介紹了 Spring Security 的基礎(chǔ)理念。本節(jié)開始我們將進入一個新的主題「認證」。在很多應(yīng)用系統(tǒng)中,認證是用戶使用系統(tǒng)的第一步,認證的目的就是系統(tǒng)對用戶身份的識別,也就是用戶回答系統(tǒng)“我是誰?”,并向系統(tǒng)證明“我就是誰”。
認證的概念不難理解,可實現(xiàn)起來卻沒那么容易,因為相互信任本身就是一件困難的事。在計算機領(lǐng)域中,似乎很少能出現(xiàn)絕對的信任,而且驗證的復(fù)雜度與執(zhí)行效率往往是相互沖突的。我們往往要在安全性與易用性之間做取舍。像社交網(wǎng)站、電子郵箱這類的應(yīng)用,一般只要輸入用戶名密碼就可以了,并且不用每次都進行登錄。但是如果是安全性要求很高的應(yīng)用,僅僅有用戶名密碼就不夠了,可能還需要 U-Key、電子證書等等。
面對不同的認證方式,我們的業(yè)務(wù)系統(tǒng)如何實現(xiàn)快速集成?如何將鑒權(quán)過程標準化?多個子業(yè)務(wù)系統(tǒng)之間如何聯(lián)動?我的認證結(jié)果是否能安全的保存下來?可見想把認證過程標準化,并能適配大多數(shù)場景也不是件輕松的事。好在 Spring Security 替我們完成了這一挑戰(zhàn)。
本節(jié)將重點討論 Spring Security 的認證基礎(chǔ)——核心認證組件。
本節(jié)所指組件是 Spring Security 在程序執(zhí)行過程中的重要單元,也就是我們在開發(fā)過程中的常用對象或結(jié)構(gòu)。Spring Security 的運轉(zhuǎn)便是通過這些組件的配合實現(xiàn)的。
2. 組件總覽
Spring Security 的認證組件可以分為三個組別:
- 存儲單元。包括:
Authentication、GrantedAuthority、SecurityContextHolder、SecurityContext; - 認證管理。包括:
AuthenticationManager、ProviderManager、AuthenticationProvider、AuthenticationEntryPoint; - 流程管理。
AbstractAuthenticationProcessingFilter及其子類。
具體組件名稱及作用如下:
| 組件名 | 簡述 |
|---|---|
| SecurityContextHolder | SecurityContextHolder 用于維護 SpringContext。 |
| SecurityContext | SecurityContext 用來存儲當(dāng)前認證用戶的信息。 |
| Authentication | 維護用戶用于認證的信息。 |
| GrantedAuthority | 認證用戶的權(quán)限信息比如角色、范圍等等。 |
| AuthenticationManager | SpringSecurity 向外提供的用于認證的 API 集合。 |
| ProviderManager | AuthenticationManager 的常見實現(xiàn)類 |
| AuthenticationProvider | 用于 ProviderManager 提供認證實現(xiàn) |
| AuthenticationEntryPoint | 用于獲取用戶認證信息 |
| AbstractAuthenticationProcessingFilter | 是認證過濾器的基礎(chǔ),用于組合認證流程 |
3. 各組件詳細說明
3.1 存儲單元
3.1.1 Authentication 和 GrantedAuthority
Authentication 是用戶的認證信息,該對象有三個核心屬性:
- principal。用戶的身份信息;
- credentials。用戶的認證憑據(jù),比如密碼,通常情況下,當(dāng)用戶完成認證后,此項內(nèi)容就會被清空;
- authorities。用戶的權(quán)限,用于更高層次的鑒權(quán)功能,通常包括角色、使用范圍等信息。該屬性基本由
GrantedAuthority實現(xiàn)。GrantedAuthority是在前述Authentication對象中所指的權(quán)限信息。在開發(fā)過程中,可以通過Authentication.getAuthorities()方法獲取。權(quán)限信息通常包括角色、范圍,或者其他擴展內(nèi)容。
Authentication 有兩個主要作用:
- 為
AuthenticationManager對象提供用于認證的信息載體; - 用于獲取某個用戶的基本信息。
3.1.2 SecurityContextHolder 和 SecurityContext
SecurityContextHolder對象是整個 Spring Security 體系的核心,它維護著SecurityContext對象。SecurityContext對象用于銜接SecurityContextHolder和Authentication對象,是對Authentication的外層封裝。- 在 Spring Security 項目中,
SecurityContextHolder對象是唯一的。

SecurityContextHolder 對象為 Spring Security 保存著所有認證用戶的信息。Spring Security 本身不關(guān)心 SecurityContextHolder 如何獲取到用戶信息,一旦其中包含用戶對象,Spring Security 就認為當(dāng)前用戶認證成功了。
由此可知,假如我們希望 Spring Security 保持認證通過狀態(tài),而不需要經(jīng)歷復(fù)雜的認證過程,最直接的方式便是往 SecurityContextHolder 里寫入用戶信息。例如:
// 第一步,創(chuàng)建 SecurityContext 對象
SecurityContext context = SecurityContextHolder.createEmptyContext();
// 第二步,為 SpringContext 注入認證信息,例如 用戶名:testUser;密碼:testPassword;角色:ROLE_TEST
Authentication authentication = new TestingAuthenticationToken("testUser", "testPassword", "ROLE_TEST");
context.setAuthentication(authentication);
// 第三步,為 SecurityContextHolder 注入當(dāng)前用戶的 SecurityContext 對象
SecurityContextHolder.setContext(context);
通過以上代碼,在 Spring Security 中加入了一個已認證的用戶。
通過 SecurityContextHolder 對象,我們也可以獲取到當(dāng)前登錄的用戶信息。例如:
// 第一步,獲取當(dāng)前線程內(nèi)的 SecurityContext 對象
SecurityContext context = SecurityContextHolder.getContext();
// 第二步,從 SecurityContext 對象中獲取用戶認證信息,如用戶名、密碼、權(quán)限
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
默認情況下,SecurityContextHolder 使用 ThreadLocal 存儲變量信息。
3.2 認證管理
3.2.1 AuthenticationManager
AuthenticationManager 為 Spring 過濾器提供認證支持 API。AuthenticationManager 的實現(xiàn)形式并沒有嚴格限制,通常情況下使用 ProviderManager。
3.2.2 ProviderManager
ProviderManager 是 AuthenticationManager 的最常用的實現(xiàn)類,它包含了一系列的 AuthenticationProvider 對象,用以判斷認證流程是否完成、認證結(jié)構(gòu)是否成功。

3.2.3 AuthenticationProvider
每個 ProviderManager 可以包含多個 AuthenticationProvider ,每個 AuthenticationProvider 提供一種認證類型,例如:DaoAuthenticationProvider 可以完成「用戶名 / 密碼」的認證,JwtAuthenticationProvider 用于完成 JWT 方式的認證。
3.2.4 AuthenticationEntryPoint
當(dāng)一個請求包含的認證信息不全時,比如未認證終端訪問受保護資源時,AuthenticationEntryPoint 對象便會發(fā)揮其作用,如跳轉(zhuǎn)到登錄頁面、返回認證要求等。
3.3 流程管理
Spring Security 用安全過濾器管理認證流程,AbstractAuthenticationProcessingFilter 是所有認證過濾器的基類。它完成了以下幾項內(nèi)容:
- 當(dāng)用戶提交認證信息,
AbstractAuthenticationProcessingFilter首先從請求信息(例如用戶名、密碼)中創(chuàng)建Authentication對象; - 將
Authentication對象傳遞給AuthenticationManager對象,用于后續(xù)認證; - 如果認證失敗,則執(zhí)行失敗流程:
- 清空 SecurityContextHolder 對象;
- 觸發(fā)
RememberMeServices.loginFail方法; - 觸發(fā)
AuthenticationFailureHandler。
- 如果認證成功,則執(zhí)行成功流程:
SessionAuthenticationStrategy登記新的登錄;- 將
Authentication對象設(shè)置到SecurityContextHolder對象中,并將SecurityContext對象保持到 Session 中; - 調(diào)用
RememberMeServices.loginSuccess方法; ApplicationEventPublisher發(fā)起事件InteractiveAuthenticationSuccessEvent
4. 小結(jié)
本小節(jié)主要講解了Spring Security 的主要組件:
Spring Security 的組件包含了「存儲單元」、「認證管理」和「流程管理」三個部分;
Spring Security 的各種認證擴展都是基于這三個部分實現(xiàn)的。
下一節(jié)我們將討論認證中最普遍的一種方式:“用戶名密碼認證”。
童雷 ·
2025 imooc.com All Rights Reserved |