spring security 認證流程:

1. 當(dāng)?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;
當(dāng)使用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的主要認證類;