spring security 認證及權限控制源碼運行流程跟蹤

一、認證流程

1、集成過程詳情看https://blog.csdn.net/qq_20475615/article/details/100132005

2、首先講默認配置的流程,我們加了spring security的配置之後,對沒有特殊處理的接口發起請求,會跳到默認的登錄頁

      

  • ① 當請求發起後,會被 UsernamePasswordAuthenticationFilter攔截,實際上幕後主使是它的爸爸AbstractAuthenticationProcessingFilter,它爸爸是掌控這個認證流程的主線

  • ② 接着它兒子 UsernamePasswordAuthenticationFilter開始幹活執行attemptAuthentication方法,兒子根據用戶輸入的賬戶密碼,構建UsernamePasswordAuthenticationToken,然後叫 AuthenticationManager工作

  • ③ AuthenticationManager接口的實現類ProviderManager承擔起責任,這裏ProviderManager 有對具體使用哪個provider來應戰有做判斷,後面我們講自定義provider的時候再說

  • ④ 接着 provider家族的 AbstractUserDetailsAuthenticationProvider和DaoAuthenticationProvider父子兵上陣

  • ⑤ 跟着開始調動UserDetailsService的實現類進行查詢用戶信息,UserDetailsService是我們集成spring security需實現的

  • ⑥ 查詢到相應數據之後,視線轉回到步驟④的 provider家族的 AbstractUserDetailsAuthenticationProvider,開始進行校驗,它的校驗有默認的內部類DefaultPreAuthenticationChecks 和DefaultPostAuthenticationChecks,利用前端用戶傳入的密碼和數據庫查詢到的密碼進行匹配,用戶傳入的我們已經在前面構建到UsernamePasswordAuthenticationToken 裏了

  • ⑦ 至於使用什麼密碼校驗規則,在配置中傳入

  • ⑧ 匹配成功後存入權限信息之類的,然後回到幕後主使AbstractAuthenticationProcessingFilter,做相應的後勤工作

  • ⑨ 假設我們在配置類配置了成功登錄處理類,則會相應的調用

3、下面講一下我們自定義filter和provider的流程,就比如最常用的我們微信或授權登錄,後臺拿到前端傳過來的code,我們去獲取openid

WxLoginFilter(模仿UsernamePasswordAuthenticationFilter繼承AbstractAuthenticationProcessingFilter) 

WxAuthProvider(模仿AbstractUserDetailsAuthenticationProvider實現AuthenticationProvider)

WxAuthenticationToken(模仿UsernamePasswordAuthenticationToken繼承AbstractAuthenticationToken)

MiniProgramLoginFilter(模仿UsernamePasswordAuthenticationFilter繼承AbstractAuthenticationProcessingFilter)

MiniProgramAuthProvider(模仿AbstractUserDetailsAuthenticationProvider實現AuthenticationProvider)

MiniProgramAuthenticationToken(模仿UsernamePasswordAuthenticationToken繼承AbstractAuthenticationToken)

修改配置類SecurityConfig

  • ② 那跟上面默認配置的差別在哪裏了,它是怎麼自動匹配我們的請求呢,用postman請求授權接口http://127.0.0.1:8090/mini/auth,這個其實就是我們配置在自定義的MiniProgramLoginFilter裏,幕後主使AbstractAuthenticationProcessingFilter操控着這一切,對url進行匹配,調用最適合的兒子來處理請求

  • ③ 前面說了兒子幹活執行attemptAuthentication方法,那兒子構建好token之後調用AuthenticationManager接口的實現類ProviderManager,這裏ProviderManager 怎麼知道來調用我們自定義的哪個provider呢?
  • 主要靠provider.supports,它根據我們在filter那裏傳入的token類型,匹配provider實現類中supports校驗的類型,一致則可以調用

  • 至於其他的流程也就跟上面的沒兩樣啦

4、總結認證流程:filter->AuthenticationManager->provider->UserDetailService->provider->filter

  1. 如果自定義了filter則根據匹配進去相應的filter,當然入口還是父類 AbstractAuthenticationProcessingFilter 的doFilter,這裏的 !this.requiresAuthentication(request, response) 則是對多個自定義filter進行請求匹配
  2. 接着到AuthenticationManager接口的實現類ProviderManager,具體選擇對應 AuthenticationProvider的實現,默認是DaoAuthenticationProvider,判斷是用 provider.supports(),每個自定義provider都會繼承supports,根據信息token類(如UsernamePasswordAuthenticationToken)和在filter傳進來的類型行判斷
  3. DaoAuthenticationProvider中的retrieveUser開始查數據庫驗證,查到之後就回去它的爸爸AbstractUserDetailsAuthenticationProvider開始check,最主要還是這個this.additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken)authentication)
  4. 最後校驗成功,this.createSuccessAuthentication(principalToReturn, authentication, user)返回,裏面還有對權限的初始化
  5. 上面步驟3和步驟4不是必須的,假如自己自定義了 provider,比如寫了微信登錄之類的,那就不需要數據庫驗證的過程,這時候沒有步驟3和4
  6. 最後的最後,返回到初始層,AbstractAuthenticationProcessingFilter中,接着將登錄信息放入session還有上下文,this.successfulAuthentication(request, response, chain, authResult)根據是否自定義了SuccessHandler或者FailHandler來調用

二、權限控制

1、權限流程

  • ① 加入權限控制,增加三個類

MyAccessDecisionManager(實現AccessDecisionManager) 

MyFilterSecurityInterceptor(繼承AbstractSecurityInterceptor)

SecurityMetadataSource(實現FilterInvocationSecurityMetadataSource)

修改配置類SecurityConfig

  • ② 當請求被MyFilterSecurityInterceptor攔截後,調用父類AbstractSecurityInterceptor的beforeInvocation方法

  • ③ 根據子類注入的 SecurityMetadataSource實現類進行處理

  • ④ 查詢到相應的系統權限,返回給AbstractSecurityInterceptor

  • ⑤ 接着調用accessDecisionManager開始進行匹配, accessDecisionManager我們開始就已經注入

  • ⑥ 匹配用戶擁有的權限和用戶的請求,如果包含則可以訪問,否則不行

2、權限控制總結:

  1. 自定義的filter並注入AccessDecisionManager的實現類,接着調用filter的父類AbstractSecurityInterceptor中的 beforeInvocation 進行操作
  2. 先獲取FilterInvocationSecurityMetadataSource的實現類中的 getAttributes 方法獲取數據庫中的權限列表,返回用戶請求的
  3. 接着調用 AccessDecisionManager 的實現類中的 decide 方法用上下文中用戶的權限和用戶請求的進行匹配,達到權限控制的目的

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章