背景
最近,公司的標準B端產品,遇到了兩個客戶的定制化需求:
1.A客戶公司要求產品需要集成他們的單點登錄,客戶還提出來,他們今年沒有這方面的預算,要求自己在我們的源碼基礎上二開。
【資料圖】
2.B客戶公司說他們集團有要求,產品都需要集成雙因子認證登錄的功能,同樣他們登錄也要求接入他們的用戶中心。
我們的產品登錄認證是基于# SpringSecurity+OAuth2.0。
看起來登錄認證,接入客戶的用戶中心這個場景在安全的大背景下,是一個普遍的需求場景了,遂納入了迭代版本,同時考慮到后續版本升級及維護成本,進行統一的設計,留好接口,做到良好的代碼隔離及擴展。
我的工作思路
1.接到這種需求,首先第一考慮的當然是搜索,github上找現成方案,hahah,沒錯,面相搜索的編程原則不能丟,用經過別人實踐的方案,或者是這個模塊的通用解決方案,不用自己想歪招~
2.當我查了半天,發現S# SpringSecurity+OAuth2.0原理解釋的文章一大堆,但是真正關于這兩個需求相關的方案很少,僅有的幾篇要么寫的不清楚,要么不是我想要的,無奈還是得自己調研,做方案設計。
tips:
SpringSecurity+OAuth2.0我只是以前作為學習了解過,最多寫過demo,之前沒有負責過登錄模塊,并且好幾年了,也只是了解寫概念和基本流程,并不足以支撐我進行方案設計和基SpringSecurity+OAuth2.0的改造。那就只能重新回顧原理去了。
這里為什么說不足以支撐我做方案設計呢,我個人認為SpringSecurity+OAuth2.0的方案,框架封閉程度太高了。
幾個概念
1.OAuth2.0
2.SpringSecurity+OAuth2.0
3.單點登錄
這幾個概念比較普遍了,不知道的也可以網上搜一下,都寫的比較透徹了。
4.雙因子登錄可能有些人不太清楚,這里重點說一下:
其實這也不是新概念了,早年的銀行U盾+用戶名密碼也是雙因子的一種。 就舉個現在C端常用的例子吧:
正常你可能用戶名+密碼就完成了登錄,但是當你某一天去外地出差,在輸入用戶名密碼后,跳轉到了另一個頁面要求你用短信驗證碼做二次認證,大概就是這么個場景。概括的說:在系統基于大數據識別到風險或者異常行為,開啟第二種登錄認證方式。
談談我的設計方案
根據需求背景,那我希望的是:
1.三方登錄集成:
SpringSecurity的用戶名密碼認證,可以基于策略模式,來實現。(基于本地的密碼認證策略,三方接口接入的)
2.雙因子登錄:
在用戶請求登錄時,增加預校驗接口,先校驗是否需要雙因子認證,如果不需要,則直接加載密碼授權模式辦法token,如果需要,則先不能辦發token,再增加一個自定義的grant_type,來進行短信驗證碼的授權模式,并頒發token。
目標出發,再看oauth2.0的工作及實現原理
由于原來的實現是授權碼模式(authorization code),那我們來看他的工作流程及原理:
我們畫出他的時序圖:
集成三方登錄
從上述時序圖來看,這個需求,我們關鍵是關注下述這個地方:
他的密碼認證的核心邏輯在DaoAuthenticationProvider類的additionalAuthenticationChecks方法
接下來,我決定重寫該類的additionalAuthenticationChecks方法,這樣就能滿足我的想法,同時原來的代碼結構不用破壞,權限等的加載邏輯也都不用動。
我的具體實現方案
自定義重寫additionalAuthenticationChecks方法
基于策略模式實現不用認證方式的加載
加載自己的CustomLoginAuthProvider
SecurityConfigurer中加入自己的configure
tips: 這里有個小坑,mark一下,我還查了好就:
雙因子登錄
還是根據調用的時序圖來看:
關于授權類型 grant_type 的解析
1.每種 grant_type 都會有一個對應的 TokenGranter 實現類。
2.所有 TokenGranter 實現類都通過 CompositeTokenGranter 中的 tokenGranters 集合存起來。
3.然后通過判斷 grantType 參數來定位具體使用那個 TokenGranter 實現類來處理授權。
關于授權登錄邏輯
1.每種 授權方式 都會有一個對應的 AuthenticationProvider 實現類來實現。
2.所有 AuthenticationProvider 實現類都通過 ProviderManager 中的 providers 集合存起來。
3.TokenGranter 類會 new 一個 AuthenticationToken 實現類,如 UsernamePasswordAuthenticationToken 傳給 ProviderManager 類。
4.而 ProviderManager 則通過 AuthenticationToken 來判斷具體使用那個AuthenticationProvider 實現類來處理授權。
5.具體的登錄邏輯由 AuthenticationProvider 實現類來實現,如 DaoAuthenticationProvider。
基于以上我這里實現了單獨的SmsGranter
關鍵詞: