一、認證流程
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
- ① 首先我們大概看一下自定義filter和provider需要做哪些工作,這裏我們弄微信登錄和小程序登錄兩個來說明,總的增加六個類,這裏只截圖,具體源碼請看這裏https://blog.csdn.net/qq_20475615/article/details/100132005
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
- 如果自定義了filter則根據匹配進去相應的filter,當然入口還是父類 AbstractAuthenticationProcessingFilter 的doFilter,這裏的 !this.requiresAuthentication(request, response) 則是對多個自定義filter進行請求匹配
- 接着到AuthenticationManager接口的實現類ProviderManager,具體選擇對應 AuthenticationProvider的實現,默認是DaoAuthenticationProvider,判斷是用 provider.supports(),每個自定義provider都會繼承supports,根據信息token類(如UsernamePasswordAuthenticationToken)和在filter傳進來的類型行判斷
- DaoAuthenticationProvider中的retrieveUser開始查數據庫驗證,查到之後就回去它的爸爸AbstractUserDetailsAuthenticationProvider開始check,最主要還是這個this.additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken)authentication)
- 最後校驗成功,this.createSuccessAuthentication(principalToReturn, authentication, user)返回,裏面還有對權限的初始化
- 上面步驟3和步驟4不是必須的,假如自己自定義了 provider,比如寫了微信登錄之類的,那就不需要數據庫驗證的過程,這時候沒有步驟3和4
- 最後的最後,返回到初始層,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、權限控制總結:
- 自定義的filter並注入AccessDecisionManager的實現類,接着調用filter的父類AbstractSecurityInterceptor中的 beforeInvocation 進行操作
- 先獲取FilterInvocationSecurityMetadataSource的實現類中的 getAttributes 方法獲取數據庫中的權限列表,返回用戶請求的
- 接着調用 AccessDecisionManager 的實現類中的 decide 方法用上下文中用戶的權限和用戶請求的進行匹配,達到權限控制的目的