在很多場景下,你的應用需要跳出Spring Security功能的邊界,,可能會需要實現(xiàn)自己的AuthenticationProvider,。回憶在第二章中AuthenticationProvider的角色,,在整個認證過程中,,它接受安全實體請求提供的憑證(即Authentication對象或authentication token)并校驗其正確性和合法性。 通過AuthenticationProvider實現(xiàn)一個簡單的單點登錄 通常,,應用允許以用戶或客戶端方式登錄,。但是,有一種場景也很常見,,尤其是在廣泛使用的應用中,,即允許系統(tǒng)中的不同用戶以多種方式登錄。 假設我們的系統(tǒng)與一個簡單的“單點登錄”提供者進行集成,,用戶名和密碼分別在HTTP頭中的j_username 和j_password發(fā)送,。除此以外,j_signature頭信息包含了用戶名和密碼的隨意編碼算法形成的字符串,,以輔助安全請求,。 【不要使用這個例子作為真實單點登錄的解決方案。這個例子很牽強,,只是為了說明實現(xiàn)一個完全自定義AuthenticationProvider的步驟,。真正的SSO解決方案顯然會更安全并涉及到幾次的握手以建立可信任的憑證。Spring Security支持幾種SSO解決方案,包括中心認證服務(CAS)和SiteMinder,,我們將會在第十章:使用中心認證服務實現(xiàn)單點登錄中介紹。實際上,Spring Security提供了一個類似的過濾器用來進行SiteMinder請求頭的認證,,即o.s.s.web.authentication.preauth.RequestHeaderAuthenticationFilter,也是這種類型功能的一個好例子,?!?/p> 對于admin用戶的登錄,我們的算法期望在請求頭中包含如下的數(shù)據:
一般來講,,AuthenticationProvider將會尋找特定的AuthenticationToken,,而后者會在過濾器鏈中位置比較靠前的servlet filter里面進行填充賦值(明確會在AuthenticationManager訪問檢查執(zhí)行之前),如下圖描述: 在這種方式中,,AuthenticationToken的提供者與其消費者AuthenticationProvider有一點脫離關系了,。所以,在實現(xiàn)自定義AuthenticationProvider時,,通常還需要實現(xiàn)一個自定義的servlet過濾器,,其作用是提供特定的AuthenticationToken,。 自定義認證token我們實現(xiàn)自定義的方法會盡可能的使用Spring Security的基本功能?;诖?,我們會擴展并增強基本類如UsernamePasswordAuthenticationToken,并添加一個新的域來存儲我們已編碼的簽名字符串,。最終的類com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationToken,,如下:
我們可以看到SignedUsernamePasswordAuthenticationToken是一個簡單的POJO類,擴展自UsernamePasswordAuthenticationToken,。Tokens并不需要太復雜——它們的主要目的就是為后面的校驗封裝憑證信息,。 實現(xiàn)對請求頭處理的servlet過濾器現(xiàn)在,我們要寫servlet過濾器的代碼,,它負責將請求頭轉換成我們新定義的token,。同樣的,我們擴展對應的Spring Security基本類,。在本例中,,o.s.s.web.authentication. AbstractAuthenticationProcessingFilter滿足我們的要求。 【基本過濾器AbstractAuthenticationProcessingFilter在Spring Security中是很多進行認證過濾器的父類(包括OpenID,、中心認證服務以及基于form的用戶名和密碼登錄),。這個類提供了標準的認證邏輯并適當織入了其它重要的資源如RememberMeServices和ApplicationEventPublisher(本章的后面將會講解到)?!?/p> 現(xiàn)在,,讓我們看一下代碼:
可以看到,這個比較簡單的過濾器查找三個已命名的請求頭,,正如我們已經規(guī)劃的那樣(如果需要的話,,可以通過bean屬性進行配置),并監(jiān)聽默認的URL /j_spring_security_filter,。正如其它的Spring Security過濾器那樣,,這是一個虛擬的URL并被我們的過濾器的基類AbstractAuthenticationProcessingFilter所識別,基于此這個過濾器采取行動嘗試創(chuàng)建Authentication token并認證用戶的請求,。 【區(qū)分參與認證token流程的各個組件,。在這個功能中,很容易被這些術語,、接口和類的名字搞暈,。代表要認證的token接口是o.s.s.core.Authentication,這個接口的實現(xiàn)將以后綴AuthenticationToken結尾,。這是一個很簡單的方式來區(qū)分Spring Security提供的認證實現(xiàn)類,。】 在本例中,我們盡可能將錯誤檢查最小化(譯者注:即參數(shù)的合法性與完整性的檢查),??赡茉趯嶋H的應用中,會校驗是否所有頭信息都提供了以及在發(fā)現(xiàn)用戶提供信息不正確的時候要拋出異?;驅τ脩暨M行重定向,。 一個細小的配置變化是需要將我們的過濾器插入到過濾器鏈中:
你可以看到過濾器代碼最后請求AuthenticationManager來進行認證。這將最終委托配置的AuthenticationProvider,,它們中的一個要支持檢查SignedUsernamePasswordAuthenticationToken,。接下來,我們需要書寫一個AuthenticationProvider來做這件事情,。 實現(xiàn)基于請求頭的AuthenticationProvider現(xiàn)在,,我們寫一個AuthenticationProvider的實現(xiàn)類,即com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationProvider,,負責校驗我們自定義Authentication token的簽名,。
你可以看到我們再次擴展了框架中的類DaoAuthenticationProvider,因為有用的數(shù)據訪問代碼仍然需要進行實際的用戶密碼校驗以及通過UserDetailsService加載UserDetails,。 這個類有些復雜,,所以我們將分別介紹其中的每個方法。 Supports方法,,是重寫父類的方法,,向AuthenticationManager指明當前AuthenticationProvider要進行校驗的期望運行時Authentication token。 接下來,,additionalAuthenticationChecks方法被父類調用,,此方法允許子類對token進行特有的校驗。這正適合我們的策略,,所以添加上我們對token新的簽名檢查,。基本上已經完成了我們自定義“簡單SSO”的實現(xiàn),,僅剩一處配置了,。 連接AuthenticationProvider 一個常見的要求就是將一個或更多的AuthenticationProvider接口連接起來,因為用戶可能會以幾種校驗方式中的某一種登錄系統(tǒng),。 因為到目前為止,,我們還沒有了解其它的AuthenticationProvider,我們可以假設以下的需求,,即使用標準的用戶名和密碼基于form的認證以及前面實現(xiàn)的自定義簡單SSO認證。當配置了多個AuthenticationProvider時,,每個AuthenticationProvider都會檢查過濾器提供給它的AuthenticationToken,,僅當這個token類型它支持時才會處理這個token。以這種方式,,你的應用同時支持不同的認證方式并不會有什么壞處,。 連接多個AuthenticationProvider實際上很簡單,。只需要在我們的dogstore-security.xml配置文件中聲明另一個authentication-provider引用。
與我們安全配置文件中引用的其它Spring bean一樣,,signedRequestAuthenticationProvider引用就是我們的AuthenticationProvider,,它將在dogstore-base.xml中與其它的Spring bean一起進行配置。
我們自定義的AuthenticationProvider的bean屬性其實都是父類所需要的,。這些也都指向了我們在AuthenticationManager的中第二個authentication-provider聲明中的那些bean,。 最終已經完成了支持這個簡單單點登錄功能的編碼和配置,至此可以給自己一個小小的喝彩,。但是,,還有一個小問題——我們應該怎樣操作請求的http頭以模擬我們的SSO認證提供者呢? 使用請求頭模擬單點登錄 盡管我們的場景比較牽強,,但是有一些商業(yè)和開源的單點登錄解決方案,,它們能夠被配置以通過HTTP請求頭發(fā)送憑證信息,最具有代表性的是CA(以前的Netegrity)SiteMinder,。 【需要特別注意的是,,與SSO方案集成的應用是不能通過用戶的直接請求訪問的。通常情況下,,SSO provider功能作為代理,,通過它確定用戶的請求流程(是安全的)或provider持有關于密碼的信息并將這些信息與單個的安全應用隔離。在沒有完全了解一個其使用的硬件,、網絡和安全設施之前,,不要部署SSO應用?!?/p> Mozilla Firefox的瀏覽器擴展,,名為Modify Headers(可以在以下地址獲得:http://modifyheaders.),是一個很簡單的工具能夠用來模擬偽造HTTP頭的請求,。以下的截圖表明了如何使用這個工具添加我們的SSO方案所希望得到的請求頭信息:
(譯者注:說實話,,作者這個實現(xiàn)自定義AuthenticationProvider的例子真的是比較牽強,,但是還算完整描述出了其實現(xiàn)方式,想深入了解AuthenticationProvider自定義的朋友,,可以參照Spring Security提供的CasAuthenticationProvider等實現(xiàn),。) 實現(xiàn)自定義AuthenticationProviders時要考慮的事項 盡管我們剛剛看到的例子并沒有闡述你想構建的AuthenticationProvider,但是任何自定義AuthenticationProvider的步驟是類似的。這個練習的關鍵在于: l 基于用戶的請求完成一個Authentication實現(xiàn)的任務一般情況下會在過濾器鏈中的某一個中進行,。取決于是否校驗憑證的數(shù)據,,這個校驗組件可能要進行擴展; l 基于一個合法的Authentication認證用戶的任務需要AuthenticationProvider的實現(xiàn)來完成,。請查看我們在第二章中討論過的AuthenticationProvider所被期望擁有的功能,; l 在一些特殊的場景下,如果未認證的session被發(fā)現(xiàn),,可能會需要自定義的AuthenticationEntryPoint,。我們將會在本章接下來的部分更多了解這個接口,也會在第十章介紹中心認證服務(CAS)時,,介紹一些AuthenticationEntryPoint的實際例子,。 如果你能時刻記住它們的角色,當你在開發(fā)應用特定的AuthenticationProvider時,,會在實現(xiàn)和調試過程中少很多的迷惑,。 |
|
來自: windli筆記 > 《Spring security》