久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

實現(xiàn)自定義的 AuthenticationProvider

 windli筆記 2013-03-06

在很多場景下,你的應用需要跳出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ù)據:

請求頭

j_username

admin

j_password

admin

j_signature

admin|+|admin

一般來講,,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,,如下:

Java代碼  收藏代碼
  1. package com.packtpub.springsecurity.security;  

  2. // imports omitted  

  3.   public class SignedUsernamePasswordAuthenticationToken   

  4. extends UsernamePasswordAuthenticationToken {  

  5.     private String requestSignature;  

  6.     private static final long serialVersionUID =   

  7.     3145548673810647886L;  

  8.   /** 

  9.    * Construct a new token instance with the given principal,  

  10. credentials, and signature. 

  11.   *  

  12.   * @param principal the principal to use 

  13.   * @param credentials the credentials to use 

  14.   * @param signature the signature to use 

  15.   */  

  16.   public SignedUsernamePasswordAuthenticationToken(String principal,  

  17.     String credentials, String signature) {  

  18.     super(principal, credentials);  

  19.     this.requestSignature = signature;  

  20.     }  

  21.   public void setRequestSignature(String requestSignature) {  

  22.     this.requestSignature = requestSignature;  

  23.     }  

  24.   public String getRequestSignature() {  

  25.     return requestSignature;  

  26.     }  

  27. }   

         我們可以看到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)在,,讓我們看一下代碼:

Java代碼  收藏代碼
  1. // imports omitted  

  2.   public class RequestHeaderProcessingFilter extends   

  3.     AbstractAuthenticationProcessingFilter {  

  4.   private String usernameHeader = "j_username";  

  5.   private String passwordHeader = "j_password";  

  6.   private String signatureHeader = "j_signature";  

  7.   protected RequestHeaderProcessingFilter() {  

  8.     super("/j_spring_security_filter");  

  9.     }  

  10.   @Override  

  11.   public Authentication attemptAuthentication   

  12.     (HttpServletRequest request,HttpServletResponse response)   

  13.     throws AuthenticationException,  

  14.       IOException, ServletException {  

  15.     String username = request.getHeader(usernameHeader);  

  16.     String password = request.getHeader(passwordHeader);  

  17.     String signature = request.getHeader(signatureHeader);  

  18.     SignedUsernamePasswordAuthenticationToken authRequest =   

  19.       new SignedUsernamePasswordAuthenticationToken   

  20.       (username, password, signature);  

  21.     return this.getAuthenticationManager().authenticate(authRequest);  

  22.     }  

  23.   // getters and setters omitted below  

  24. }   

           可以看到,這個比較簡單的過濾器查找三個已命名的請求頭,,正如我們已經規(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行重定向,。

一個細小的配置變化是需要將我們的過濾器插入到過濾器鏈中:

Xml代碼  收藏代碼
  1. <http auto-config="true" ...>  

  2.   <custom-filter ref="requestHeaderFilter"   

  3.   before="FORM_LOGIN_FILTER"/>  

  4. </http>  

 你可以看到過濾器代碼最后請求AuthenticationManager來進行認證。這將最終委托配置的AuthenticationProvider,,它們中的一個要支持檢查SignedUsernamePasswordAuthenticationToken,。接下來,我們需要書寫一個AuthenticationProvider來做這件事情,。

實現(xiàn)基于請求頭的AuthenticationProvider

現(xiàn)在,,我們寫一個AuthenticationProvider的實現(xiàn)類,即com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationProvider,,負責校驗我們自定義Authentication token的簽名,。

Java代碼  收藏代碼
  1. package com.packtpub.springsecurity.security;  

  2. // imports omitted  

  3.   public class SignedUsernamePasswordAuthenticationProvider   

  4.   extends DaoAuthenticationProvider {  

  5.     @Override  

  6.     public boolean supports(Class<? extends Object> authentication) {  

  7.       return (SignedUsernamePasswordAuthenticationToken .class.isAssignableFrom(authentication));  

  8.     }  

  9.   @Override  

  10.   protected void additionalAuthenticationChecks   

  11.   (UserDetails userDetails,  

  12.     UsernamePasswordAuthenticationToken authentication)  

  13.     throws AuthenticationException {  

  14.     super.additionalAuthenticationChecks   

  15.     (userDetails, authentication);  

  16.     SignedUsernamePasswordAuthenticationToken signedToken =   

  17.       (SignedUsernamePasswordAuthenticationToken) authentication;  

  18.     if(signedToken.getRequestSignature() == null) {  

  19.       throw new BadCredentialsException(messages.getMessage(  

  20.       "SignedUsernamePasswordAuthenticationProvider  

  21.       .missingSignature", "Missing request signature"),  

  22.       isIncludeDetailsObject() ? userDetails : null);  

  23.     }  

  24. // calculate expected signature   

  25.   if(!signedToken.getRequestSignature()   

  26.   .equals(calculateExpectedSignature(signedToken))) {  

  27.   throw new BadCredentialsException(messages.getMessage   

  28.   ("SignedUsernamePasswordAuthenticationProvider   

  29.   .badSignature", "Invalid request signature"),  

  30.   isIncludeDetailsObject() ? userDetails : null);  

  31.   }  

  32. }  

  33. private String calculateExpectedSignature   

  34.   (SignedUsernamePasswordAuthenticationToken signedToken) {  

  35.     return signedToken.getPrincipal() + "|+|" +   

  36.     signedToken.getCredentials();  

  37.   }  

  38. }  

 你可以看到我們再次擴展了框架中的類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引用。

Xml代碼  收藏代碼
  1. <authentication-manager alias="authenticationManager">  

  2.   <authentication-provider ref= "signedRequestAuthenticationProvider"/>  

  3.   <authentication-provider user-service-ref="jdbcUserService">  

  4.     <password-encoder ref="passwordEncoder" >  

  5.       <salt-source ref="saltSource"/>  

  6.     </password-encoder>  

  7.   </authentication-provider>  

  8. </authentication-manager>  

          與我們安全配置文件中引用的其它Spring bean一樣,,signedRequestAuthenticationProvider引用就是我們的AuthenticationProvider,,它將在dogstore-base.xml中與其它的Spring bean一起進行配置。

Xml代碼  收藏代碼
  1. <bean id="signedRequestAuthenticationProvider"  class="com.packtpub.springsecurity.security   

  2. .SignedUsernamePasswordAuthenticationProvider">  

  3.   <property name="passwordEncoder" ref="passwordEncoder"/>  

  4.   <property name="saltSource" ref="saltSource"/>  

  5.   <property name="userDetailsService" ref="jdbcUserService"/>  

  6. </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方案所希望得到的請求頭信息:



 將所有的頭信息標示為Enabled,,訪問這個URL:http://localhost:8080/JBCPPets/j_spring_security_filter,會發(fā)現(xiàn)我們能夠自動登錄系統(tǒng),。你可能也會發(fā)現(xiàn)我們給予form的登錄還能繼續(xù)可用,,這是因為保留了這兩個AuthenticationProvider實現(xiàn)以及過濾器鏈中對應的過濾器。

(譯者注:說實話,,作者這個實現(xiàn)自定義AuthenticationProvider的例子真的是比較牽強,,但是還算完整描述出了其實現(xiàn)方式,想深入了解AuthenticationProvider自定義的朋友,,可以參照Spring Security提供的CasAuthenticationProvider等實現(xiàn),。)

實現(xiàn)自定義AuthenticationProviders時要考慮的事項

         盡管我們剛剛看到的例子并沒有闡述你想構建的AuthenticationProvider,但是任何自定義AuthenticationProvider的步驟是類似的。這個練習的關鍵在于:

基于用戶的請求完成一個Authentication實現(xiàn)的任務一般情況下會在過濾器鏈中的某一個中進行,。取決于是否校驗憑證的數(shù)據,,這個校驗組件可能要進行擴展;

基于一個合法的Authentication認證用戶的任務需要AuthenticationProvider的實現(xiàn)來完成,。請查看我們在第二章中討論過的AuthenticationProvider所被期望擁有的功能,;

在一些特殊的場景下,如果未認證的session被發(fā)現(xiàn),,可能會需要自定義的AuthenticationEntryPoint,。我們將會在本章接下來的部分更多了解這個接口,也會在第十章介紹中心認證服務(CAS)時,,介紹一些AuthenticationEntryPoint的實際例子,。

如果你能時刻記住它們的角色,當你在開發(fā)應用特定的AuthenticationProvider時,,會在實現(xiàn)和調試過程中少很多的迷惑,。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報,。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約