spring security 認證流程:
1. 當?shù)卿洉r遮糖,請求會被UsernamePasswordAuthenticationFilter 攔截麻汰, 獲取用戶名和密碼速客,封裝成UsernamePasswordAuthenticationToken,并交給AuthenticationManager(認證核心接口)去認證五鲫;
2. ProviderManager 是AuthenticationManager接口的實現(xiàn)類溺职,也就是驗證UsernamePasswordAuthenticationToken時交給它來處理。
3. ProviderManager 的authenticate(authentication) 方法位喂,是驗證UsernamePasswordAuthenticationToken的核心方法浪耘;從源碼可以得知:ProviderManager? 有 一個屬性為:List providers; 從名稱就可以看出,是一個認證器的集合塑崖;所以authenticate(authentication)方法的主要邏輯就是遍歷providers七冲, support(UsernamePasswordAuthenticationToken)的AuthenticationProvider 會去做相應(yīng)的認證;
AuthenticationProvider 認證用戶三步走原則:
(1)獲取用戶信息
(2)檢查用戶“是否被禁用”规婆,“是否被鎖定”澜躺,“是否過期”
(3)校驗用戶名和密碼
4. 通過驗證返回Authentication
5. 通過驗證返回Authentication
6. 通過驗證返回Authentication到 AbstractAuthenticationProcessingFilter
7. successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) 發(fā)布登錄成功;
主要邏輯為:
(1)Authentication保存到SecurityContext中聋呢; 源碼:SecurityContextHolder.getContext().setAuthentication(authResult);
(2)如果配合記住密碼苗踪,則會記住密碼;??? 源碼:this.rememberMeServices.loginSuccess(request, response, authResult);
?(3)? 請求之前未登錄狀態(tài)下請求的網(wǎng)址削锰;??? 源碼:this.successHandler.onAuthenticationSuccess(request, response, authResult)
說明:SecurityContextHolder.getContext().setAuthentication(authResult)通铲,底層源碼是使用new ThreadLocal() 存儲的,如果不了解?ThreadLocal器贩,請自行查閱颅夺;
spring security 權(quán)限校驗流程:
1. 第一次請求http://localhost:8088/persons方法時朋截,UsernamePasswordAuthenticationFilter? 不會攔截,因為UsernamePasswordAuthenticationFilter? 只會攔截/login 且為POST,? 但是會被AnonymousAuthenticationFilter攔截吧黄,主要做的就是SecurityContextHolder.getContext().setAuthentication(AnonymousAuthenticationToken)部服,具體請看源碼;然后會進入到FilterSecurityInterceptor過濾器拗慨;FilterSecurityInterceptor 過濾器才是真正控制訪問權(quán)限的Filter廓八;
2. super.beforeInvocation(fi) 主要邏輯:
1)Authentication authenticated =this.authenticateIfRequired();?? 獲取token,從SecurityContextHolder.getContext()? 獲得
2)this.accessDecisionManager.decide(authenticated, object,attributes); ******這個才是重中之重*****作用就是判斷是否有訪問權(quán)限赵抢;
?3. this.accessDecisionManager.decide(authenticated, object,attributes);會拋出AccessDeniedException |AuthenticationException異常剧蹂,并被ExceptionTranslationFilter攔截,
如果為AccessDeniedException ,跳轉(zhuǎn)到未授權(quán)頁面
如果為AuthenticationException烦却,跳轉(zhuǎn)登錄頁面
4. 由于未登錄跳轉(zhuǎn)到登錄頁
5. 填寫用戶名和密碼再次請求宠叼,會走上面的認證流程;? 認證流程走完其爵,最終還是會走到FilterSecurityInterceptor? 攔截器冒冬;然后還是會從? 2) 流程開始走,不同的是這回已經(jīng)登錄摩渺,所以Authentication authenticated =this.authenticateIfRequired();獲取到的是包含用戶數(shù)據(jù)简烤,以及權(quán)限的信息;然后還是會走this.accessDecisionManager.decide(authenticated, object,attributes); 不拋出異常則到 第6步驟证逻, 否則還是會從3 步驟開始
?6. 訪問到/persons 接口乐埠,進入到Controller 中;
以上流程圖源自:
http://www.spring4all.com/article/439
http://www.spring4all.com/article/458
關(guān)鍵的類和接口介紹:
AbstractAuthenticationProcessingFilter 類:在不同maven包下的展現(xiàn)形式:
spring-boot-starter-security包下:
spring-security-oauth2包下:
可以看出多了一個OAuth2ClientAuthenticationProcessingFilter和ClientCredentialsTokenEndpointFilter囚企;
當使用Oauth2認證時,主要走的兩個Filter瑞眼;
AuthenticationManager 接口:認證時主要是PrividerManager 實現(xiàn)類去做認證龙宏;
PrividerManager 實現(xiàn)類中主要的方法和屬性介紹:
認證器集合:providers
authenticate 方法:
1. 遍歷認證器.
2.判斷認證器是否支持token的認證
3.如果支持,進行具體的認證邏輯
AuthenticationProvider 接口:
AbstractUserDetailsAuthenticationProvider 抽象類:
authenticate 方法:
子類實現(xiàn)retrieveUser 方法伤疙,通過不同的方式獲取UserDetails银酗;
DaoAuthenticationProvider 實現(xiàn)類(去實現(xiàn)retrieveUser ):
retrieveUser方法:
通過UserDetailsService 對象獲取UserDetails對象;
UserDetailsService? 屬性:
UserDetailsService 接口:
spring-boot-starter-security包下:
spring-security-oauth2包下:
可以看出在spring-security-oauth2包下多一個ClientDetailsUserDetailsService類徒像,這個也就是spring security實現(xiàn)Oauth2的主要認證類黍特;