Acegi框架介紹(二)

用戶認證過程   Acegi支持多種方式的用戶認證:如典型的基於數據庫的認證、基於LDAP的認證、基於Yale中心認證等方式。不同的認證環境擁有不同的用戶認證方式,現在我們先拋開這些具體的細節,考察一下Acegi對受限資源進行訪問控制的典型過程:     1.你點擊一個鏈接訪問一個網頁;     2.瀏覽器發送一個請求到服務器,服務器判斷出你正在訪問一個受保護的資源;     3.如果此時你並未通過身份認證,服務器發回一個響應提示你進行認證——這個響應可能是一個HTTP響應代碼,抑或重定向到一個指定頁面;     4.根據系統使用認證機制的不同,瀏覽器或者重定向到一個登錄頁面中,或者由瀏覽器通過一些其它的方式獲取你的身份信息(如通過BASIC認證對話框、一個Cookie或一個X509證書);     5.瀏覽器再次將用戶身份信息發送到服務器上(可能是一個用戶登錄表單的HTTP POST信息、也可能是包含認證信息的HTTP報文頭);     6.服務器判斷用戶認證信息是否有效,如果無效,一般情況下,瀏覽器會要求你繼續嘗試,這意味着返回第3步。如果有效,則到達下一步;     7.服務器重新響應第2步所提交的原始請求,並判斷該請求所訪問的程序資源是否在你的權限範圍內,如果你有權訪問,請求將得到正確的執行並返回結果。否則,你將收到一個HTTP 403錯誤,這意味着你被禁止訪問。     在Acegi框架裏,你可以找到對應以上大多數步驟的類,其中ExceptionTranslationFilter、AuthenticationEntryPoint、AuthenticationProvider以及Acegi的認證機制是其中的代表者。     ExceptionTranslationFilter是一個Acegi的Servlet過濾器,它負責探測拋出的安全異常。當一個未認證用戶訪問服務器 時,Acegi將引發一個Java異常。Java異常本身對HTTP請求以及如何認證用戶是一無所知 的,ExceptionTranslationFilter適時登場,對這個異常進行處理,啓動用戶認證的步驟(第3步)。如果已認證用戶越權訪問一個資 源,Acegi也將引發一個Java異常,ExceptionTranslationFilter則將這個異常轉換爲HTTP 403響應碼(第7步)。可見,Acegi通過異常進行通訊, ExceptionTranslationFilter接收這些異常並作出相應的動作。     當ExceptionTranslationFilter通過Java異常發現用戶還未認證時,它到底會將請求重定向哪個頁面以要求用戶提供認證信息呢? 這通過諮詢AuthenticationEntryPoint來達到目的——Acegi通過AuthenticationEntryPoint描述登錄頁 面。     當你的瀏覽器通過HTTP表單或HTTP報文頭向服務器提供用戶認證信息時,Acegi需要將這些信息收集到Authentication中,Acegi 用“認證機制”描述這一過程。此時,這個新生成Authentication只包含用戶提供的認證信息,但並未通過認證。 AuthenticationProvider 負責對Authentication進行認證。AuthenticationProvider究竟如何完成這一過程呢?請回憶一下上節我們所介紹的 UserDetails和UserDetailsService,大多數AuthenticationProvider通過 UserDetailsService獲取和未認證的Authentication對應的UserDetails並進行匹配比較來完成這一任務。當用戶認 證信息匹配時,Authentication被認爲是有效的,AuthenticationProvider進一步將UserDetails中權限、 ACL等信息拷貝到Authentication。 當Acegi通過認證機制收集到用戶認證信息並填充好Authentication後,Authentication將被保存到SecurityContextHolder中並處理用戶的原始請求(第7步)。     你完全可以拋開Acegi的安全機制,編寫自己的Servlet過濾器,使用自己的方案構建Authentication對象並將其放置到SecurityContextHolder中。也許你使用了CMA(Container Managed Authentication:容器管理認證),CMA允許你從ThreadLocal或JNDI中獲取用戶認證信息,這時你只要獲取這些信息並將其轉換爲Authentication就可以了。  安全對象訪問控制       Acegi稱受保護的應用資源爲“安全對象”,這包括URL資源和業務類方法。我們知道在Spring AOP中有前置增強、後置增強、異常增強和環繞增強,其中環繞增強的功能最爲強大——它不但可以在目標方法被訪問前攔截調用,還可以在調用返回前改變返回 的結果,甚至拋出異常。Acegi使用環繞增強對安全對象進行保護。     Acegi通過AbstractSecurityInterceptor爲安全對象訪問提供一致的工作模型,它按照以下流程進行工作:     1. 從SecurityContext中取出已經認證過的Authentication(包括權限信息);     2. 通過反射機制,根據目標安全對象和“配置屬性”得到訪問目標安全對象所需的權限;     3. AccessDecisionManager根據Authentication的授權信息和目標安全對象所需權限做出是否有權訪問的判斷。如果無權訪問,Acegi將拋出AccessDeniedException異常,否則到下一步; 4. 訪問安全對象並獲取結果(返回值或HTTP響應); 5. AbstractSecurityInterceptor可以在結果返回前進行處理:更改結果或拋出異常。  

圖 6 AbstractSecurityInterceptor工作流程

    安全對象和一般對象的區別在於前者通過Acegi的“配置屬性”進行了描述,如“/view.jsp=PRIV_COMMON”配置屬性就將“ /view.jsp”這個URL資源標識爲安全對象,它表示用戶在訪問/view.jsp時,必須擁有PRIV_COMMON這個權限。配置屬性通過 XML配置文件,註解、數據庫等方式提供。安全對象通過配置屬性表示爲一個權限,這樣,Acegi就可以根據Authentication的權限信息獲知 用戶可以訪問的哪些安全對象。     根據安全對象的性質以及具體實現技術,AbstractSecurityInterceptor擁有以下三個實現類:  FilterSecurityInterceptor:對URL資源的安全對象進行調用時,通過該攔截器實施環繞切面。該攔截器使用Servlet過濾器實現AOP切面,它本身就是一個Servlet過濾器;  MethodSecurityInterceptor:當調用業務類方法的安全對象時,可通過該攔截器類實施環繞切面;  AspectJSecurityInterceptor:和MethodSecurityInterceptor類似,它是針對業務類方法的攔截器,只不過它通過AspectJ實施AOP切面。

Acegi版本升級的一些重大變化      Acegi項目開始於2003年,Acegi團隊在發佈新版本時非常謹慎,在本書寫作之時,Acegi最新版本爲1.0.3。在此之前Acegi已經發布 了10多個預覽版本,由於Acegi框架優異的表現,許多大型應用早在Acegi 1.0正式版本發佈之前(2006年5月),就已經採用Acegi框架作爲其安全訪問控制的解決方案。     在Acegi社區裏,來自世界各地衆多優秀的安全領域專家對Acegi的改進和發展獻計獻策,Acegi團隊廣泛聽取並吸收各種有益的建議,將它們融入到Acegi的框架中,使Acegi成爲構建在Spring基礎上企業應用的首選安全控制框架。 Acegi 1.0.3版本相比於早期預覽版本發生了很大的變化,對於需要進行Acegi版本的項目來說,瞭解這一變化特別重要。下面,我們列出Acegi的一些重大的升級更新:  包名的更新:在0.9.0及之前的版本中,Acegi採用net.sf.acegisecurity包名前綴,在1.0.0版本之後更改爲 org.acegisecurity(Hibernate也走過相同的道路,好在Acegi在正式版本發佈之時就完成了這種轉變);  ACL模塊的調整:ACL模塊發生了重大的調整,Acegi團隊接收了社區大量關於ACL模塊的反饋意見,重新設計了ACL模塊的底層結構,在性能、封裝 性、靈活性上得到了質的提升。事實上,Acegi使用org.acegisecurity.acls包代替了原來的 org.acegisecurity.acl包,後者將在後期的版本中刪除,由於這種傷筋動骨的變化,將很難兼容原來ACL模塊。不過,目前基於新框架的 ACL模塊還沒有進行充分的測試,Acegi承諾在1.1.0版本發佈時提供最終的實現;  刪除了ContextHolder及其相關類:在Acegi 0.9版本中,ContextHolder及其相關類被徹底從Acegi項目中刪除。ContextHolder可以在多個HTTP請求中共享同一個 ThreadLocal,這和Spring提倡的ThreadLocal只應在同一線程中共享相悖。現在,Acegi使用 SecurityContextHolder替換ContextHolder,它的生命週期是一個HTTP 請求;  使用FilterChainProxy同時代理多個過濾器:在早期的版本中,Acegi通過FilterToBeanProxy將web.xml中的 Servlet過濾器定義轉移到Spring容器中。這比直接在web.xml中配置Servlet過濾器要方便一些,但是Acegi框架往往需要定義多 個Servlet過濾器,使web.xml配置文件變得冗長難看。在Acegi 0.8版本中提供FilterChainProxy,它可以同時代理多個Servlet過濾器並保證過濾器的順序。因此在新版本 中,FilterChainProxy成爲推薦的選擇。   

小結     Acegi是Spring項目下一個成熟的安全訪問控制框架,它允許利用了Spring IoC的AOP的功能完成安全對象的訪問控制。在Acegi框架中,SecurityContextHolder處於非常核心的位置,它是存放認證管理器 用戶安全信息SecurityContext的“容器”,SecurityContext保存着用戶安全訪問控制所需的信息,直接被訪問決策管理器使用。 HttpSessionContextIntegrationFilter通過在SecurityContextHolder和HttpSession中 擺渡SecurityContext,使多個請求線程可以共享同一個SecurityContext。

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