真誠的感謝作者:本文來源https://www.jianshu.com/p/e98cdf23b991
本期任務清單
1. 了解UsernamePasswordAuthenticationFilter的職責和實現
UsernamePasswordAuthticationFilter類說明
UsernamePasswordAuthticationFilter 是AbsractAuthenticationProcessonFilter針對使用用戶名和密碼進行身份驗證而定制化的一個過濾器。
在一開始我們我們先通過下面的配圖來回憶以下我們的老朋友AbstractAuthticationProcessingFilter在框架中的角色是和職責
AbstractAuthencationProcessiongFilter的人生

AbstractAuthenticationProcessinigFilter在整個身份驗證的流程中主要的處理工作就是所有與Web資源相關的事情,並且將其封裝成Authenticaton對象,最后調用AuthenticationManager的驗證方法。所以UsernamePasswrodAuthenticationFilter的共工作大致也是如此。只不過在這個場景下更加明確了Authenticaton對象的封裝數據的來源和形式-------使用用戶名和密碼。
接下來我們在對UsernamePasswordAuthenticationFilter的屬性和方法做一個快速的了解,UsernamePasswordAuthenticationFilter 繼承擴展了AbstractAuthenticationProcessiongFilter,相對AbstractAuthenticationProcessinFilter而言主要有以下幾個改動
1. 屬性中增加了username和password字段
2. 強制只對post請求應用。
3. 重寫了attemptAuthentication身份驗證的入口方法。

封裝用戶名和密碼的基石:UsernamePasswordAuthticationToken
在UsernamePasswordAuthenticationfilter的屬性生命中二外增加了username和password的冬季很容易明白。即需要從HttpRequest中獲取的對應的參數字段,並將其封裝進Authenticaton中,傳遞給AuthenticationManager進行身份驗證。這里讓我們回顧以下Authentication到底是什么,Authentication是一個接口生命,一個特定的行為的聲明,他並不是一個類,沒有辦法實例化為對象進行傳遞,所以我們需要對Authenticaon進行實現,使其可以被實例化。

在UsernamePasswordAuthticationFilter的身份驗證設計里,我們需要驗證協議用簡單的語言可以描述為,給我一組用戶名和密碼,如果匹配,那么久算驗證成功,用戶名即是一個可以唯一標識不同用戶的字段,而密碼則是檢驗當前的身份驗證是否正確的憑證。在SpringSecurity中邊將使用username和password 封裝成Authentication的實現生命為了

usernamePasswordAuthenticationtoken繼承了AbstractAuthenticationtoken抽象類,其主要與AbstractAuthenticationtoken的區別是針對用戶名和密碼約定進行了一定的封裝,將username復制到了principal,而將password賦值到了credentials.
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; this.credentials = credentials; super.setAuthenticated(true); // must use super, as we override }
通過UsernamePasswordAuthenticationtoken實例化了Authentication接口,繼而按照流程,將其傳遞給了AuthenticationManager 調用身份驗證的核心完成相關的工作。
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest);
以上將來自HTTP請求中的參數按照預先的約定放入賦值給Authentication指定屬性,便是UsernamePasswordAuthenticationFilter部分最主要的改動。
驗證核心的工作者:AuthenticationProvider
web層的工作已經完成了,Authentication接口的實現類UsernnamePasswordAuthenticationtoken通過authenticationManager提供的方法做為參數傳遞到了核心驗證的核心組件中。
我們曾多次強調過一個設計概念:AuthenticationManager接口設計上並不是用於完成特定的身份驗證工作,。而是調用其所配發的AuthenticationProvier接口去實現的。
那么這里有一個疑問,針對接口生命參數生命的Authentication,針對不同的驗證協議的AuthenticationProviderde 的實現類完成我們對應的工作。並且AuthenticationManager是如何直到哪個AuthenticationProvider需要哪個Authentication的。
哦我們首先復習以下AuthenticationProvider接口的聲明

AuthenticationProvider只包含兩個方法聲明,核心驗證方法入口:
Authentication authenticate(Authentication authentication) throws AuthenticationException;
另外一個便是讓AuthenticationManger可以通過調用該方法分表當前AuthenticationProvider是否是完成響應驗證工作的supports方法:
oolean supports(Class<?> authentication);
簡單的描述便是AuthenticationProvier只提供兩個方法,一個是他能不能驗證當前的Authentication,還有便是讓他去驗證當前的Authentication.
對於Authenticationprovider整個體系能說的非常多,本期只對我們需要了解的AuthticationProvier中兩個接口聲明的方法做個簡單的說明。其他部分以后單獨對AuthticationProvider體系介紹時在做進一步召開
是否支持當前的驗證協議:Boolean supports(Class<?> authentication)
在spring Security 中唯一AuthenticationManager的實現類ProviderManager,在處理authenticate身份驗證入歐方法時,首先第一個解決的問題便是:我們手下哪個AuthenticationProvider能驗證當前的Authentication?為此ProviderManager便會對其所有的AuthenticationProvider做supports方法檢查,正到AuthenticatonProvider能在supoorts方法被調用返回true.
我們了解了框架上的設計邏輯,先要直到水能處理當前的身份驗證信息,在要求他進行驗證工作。
回到我們的場景上來UsernamePasswordAuthenticationFilter已經封裝好了igeUsernamePasswordAuthenticationToken傳遞給了providerManager.緊接着當前ProviderManager正焦頭爛額的詢問哪個Authenticationprovider能支持這個Authentication實現,此時的provider正如下圖一樣困惑

在ProviderManager的視角里,所有的Authentication實現類都布局名,他不僅不能通過自身完成驗證工作,也不能獨立完成判斷是否支持工作。而是統統交給AuthenticationProvider去完成。而不同的AuthentticationProvider開發初衷都是為了支持某種驗證協議,所以在特定的AuthenticationProvider的視角中,他只關心當前Authentication是不是他預先設計處理的類型即可。
在使用用戶用戶名和密碼的驗證場景中,驗證使用的用戶名和密碼被封裝成了usernamepasswordAuthenticationtoken對象,SpringSecurity 邊為了向UsernamePasswordAuthenticationToken對象在核心層提供了相關的驗證服務
小結:
我們先來總結下,出現針對用戶名和密碼擴展過的類和其為何被擴展的原因
1. UsernamePasswordAuthenticationfilter擴展了AubstarctAuthenticationProcessionFilter,因為需要因為需要從HTTP從指定的參數中獲取用戶名和密碼,並且傳遞給驗證核心
2.
- UsernamePasswordAuthenticationToken擴展Authentication,因為我們設計了一套約定將用戶名和密碼放入了指定的屬性中以便核心讀取使用;
- DaoAuthenticationProvider 擴展AuthenticationProvider,因為我們需要在核心中對UsernamePasswordAuthenticationToken進行處理,並按照約定讀出用戶名和密碼使其可以進行身份驗證操作。
結尾
本章的重點是介紹特定場景下框架是如何通過擴展指定組件來完成預設驗證邏輯的交互過程。其實整個驗證工作核心部分是在DaoAuthenticationProvider中進行完成的,但是這部分內容涉及到具體的驗證協議的實現邏輯非常復雜,本期就暫時略過,在一下期中我們將對驗證核心最重要的組件AuthenticationProvider其依賴的組件和對應職責做一個全面的講解。
我們下期再見。
鏈接:https://www.jianshu.com/p/e98cdf23b991
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
