狼愛上貍

          我胡漢三又回來了

          acegi,IBM的Acegi Security System(3)

          2007 年 10 月 18 日

          本文是 Acegi Security Systerm 介紹的最后一部分(共三部分),Bilal Siddiqui 將向您介紹如何保護(hù)對 Java 類實(shí)例的訪問,從而結(jié)束本系列文章。通過本文了解為何需要對 Java™ 類的訪問進(jìn)行保護(hù),Spring 如何創(chuàng)建和保護(hù)對 Java 類實(shí)例的訪問以及如何對 Acegi 進(jìn)行配置以實(shí)現(xiàn) Java 應(yīng)用程序的類安全性。

          這期共分三部分的系列文章介紹了如何使用 Acegi 安全系統(tǒng)保護(hù) Java 企業(yè)應(yīng)用程序。系列文章的 第 1 部分 簡單介紹了 Acegi 并解釋如何使用其內(nèi)置的安全過濾器實(shí)現(xiàn)一個(gè)簡單的、基于 URL 的安全系統(tǒng)。第 2 部分 介紹了如何編寫訪問控制策略并將其保存到一個(gè) LDAP 目錄服務(wù)器,以及如何配置 Acegi 來與目錄服務(wù)器進(jìn)行交互,從而實(shí)現(xiàn)訪問控制策略。第 3 部分(也是本系列的最后一篇文章)將演示如何在企業(yè)應(yīng)用程序中使用 Acegi 保護(hù)對 Java 類實(shí)例的訪問。

          首先我將介紹何時(shí)需要對 Java 類訪問進(jìn)行保護(hù),包括文中引用的兩個(gè)典型企業(yè)應(yīng)用程序場景。之后,我將解釋 Spring 的反轉(zhuǎn)控制(IOC)框架如何創(chuàng)建可從 JSP 或 servlet 訪問的 Java 類實(shí)例。我還將介紹有關(guān) bean 代理 的重要概念,Spring 正是使用它過濾對 Java 類的訪問。最后,我將介紹如何對 Acegi 的方法安全性攔截器進(jìn)行配置以控制對 Java 類的訪問。我將對 第 2 部分 中的示例程序進(jìn)行增強(qiáng),為實(shí)現(xiàn)安全的 Java 對象提供支持,從而結(jié)束本系列的最后一篇文章。

          由于本文的討論構(gòu)建在本系列前兩部分的內(nèi)容之上,因此會(huì)經(jīng)常引用到 第 1 部分第 2 部分 中的討論和示例。因此,在繼續(xù)閱讀本文之前,在其他瀏覽器窗口中打開前兩期文章將有助于理解本文內(nèi)容。

          保護(hù) Java 類的用例

          您可能還記得,我曾在本系列的開頭部分簡單介紹了 企業(yè)應(yīng)用程序安全性。在那次討論中我曾提到過一種場景,其中 URL 安全性并不能完全滿足這種場景的安全需求:

          假設(shè)有這樣一個(gè) PDF 文檔,其中包含了某制造業(yè)公司生產(chǎn)的特定產(chǎn)品的數(shù)據(jù)。文檔的一部分包含了設(shè)計(jì)數(shù)據(jù),將由公司設(shè)計(jì)部分進(jìn)行編輯和更新。文檔另一部分包含生產(chǎn)經(jīng)理將使用到的生產(chǎn)數(shù)據(jù)。對于此類場景,需要實(shí)現(xiàn)更加細(xì)粒度的安全性,對文檔的不同部分應(yīng)用不同的訪問權(quán)限。

          在繼續(xù)閱讀之前,請考慮更多的應(yīng)用程序場景,除了實(shí)現(xiàn) URL 安全性以外,這些場景還要求您對單獨(dú)的類訪問進(jìn)行保護(hù)。

          業(yè)務(wù)自動(dòng)化

          業(yè)務(wù)自動(dòng)化應(yīng)用程序中的工作流由多個(gè)流程組成。例如,病理學(xué)實(shí)驗(yàn)室中執(zhí)行血液測試的工作流由若干個(gè)步驟組成,其中每個(gè)步驟可看作一個(gè)業(yè)務(wù)流程:

          1. 工作人員從病人處采集血液樣本并為其分配一個(gè) ID。
          2. 實(shí)驗(yàn)室技術(shù)人員對樣本進(jìn)行必要的測試并準(zhǔn)備測試結(jié)果。
          3. 由具備相應(yīng)資格的病理學(xué)專家根據(jù)測試結(jié)果編寫測試報(bào)告。

          很明顯,每個(gè)流程分別由單獨(dú)的授權(quán)用戶執(zhí)行。未授權(quán)的用戶則無權(quán)執(zhí)行流程。例如,實(shí)驗(yàn)室研究人員只負(fù)責(zé)準(zhǔn)備試驗(yàn)結(jié)果,而無權(quán)編寫測試報(bào)告。

          幾乎所有的業(yè)務(wù)自動(dòng)化應(yīng)用程序都普遍使用授權(quán)的業(yè)務(wù)流程。通常,每個(gè)業(yè)務(wù)流程被實(shí)現(xiàn)為一個(gè) Java 類,并且需要使用合適的訪問控制策略對所有類實(shí)施保護(hù)。

          企業(yè)對企業(yè)(Business-to-business)集成

          Business-to-business (B2B) 集成指一種常見的場景,其中的兩個(gè)企業(yè)實(shí)體需要彼此公開各自的特定功能。例如,賓館可能向旅游公司公開其房間預(yù)訂功能,而后者使用該功能為游客預(yù)訂空閑的房間。作為合作伙伴的旅游公司可能具有一個(gè)特定的訂房率。在這個(gè)場景中,賓館的訂房系統(tǒng)必須先對旅游公司進(jìn)行身份驗(yàn)證,然后才能允許他們訪問所選擇的類,以便按照特定的訂房率進(jìn)行房間預(yù)訂。





          回頁首


          使用 Spring 創(chuàng)建 Java 對象

          現(xiàn)在您已經(jīng)了解了對 Java 類示例的訪問進(jìn)行保護(hù)的重要性。在介紹能夠?qū)崿F(xiàn)更高級安全性的 Acegi 新功能之前,我將引導(dǎo)您回顧 Spring 框架的幾個(gè)關(guān)鍵特性,您需要了解這些內(nèi)容才能繼續(xù)后文的示例。

          首先對一些 Java 類進(jìn)行配置并執(zhí)行實(shí)例化。第 1 部分 曾介紹過,Java 類在 Spring 的 XML 配置文件中進(jìn)行配置。在 Spring 配置文件中配置 Java 類的過程與 Acegi 過濾器的配置過程完全相同,因此這里不多做介紹。相反,我們將查看清單 1,它展示了名為 publicCatalog 的 bean 的配置:


          清單 1. Acegi XML 配置文件
                      <beans>
                      <bean id="publicCatalog"
                      class="com.catalog.PublicCatalog" />
                      <!--Other bean tags -->
                      <beans>
                      

          了解 Spring 的 IOC 框架如何從 XML 配置文件讀取 Java 類信息以及如何進(jìn)行實(shí)例化,這一點(diǎn)非常重要。您可能還記得,我在系列文章的 第 1 部分 中使用一個(gè) web.xml 文件配置 <listener> 標(biāo)記,它指向名為 ContextLoaderListener 的類。ContextLoaderListener 裝載 Spring 的 IOC 框架并創(chuàng)建 Java 對象。您可以參考 第 1 部分的清單 8 查看全部內(nèi)容。圖 1 也對此進(jìn)行了描述:


          圖 1. 裝載 Spring 的 IOC 框架并創(chuàng)建 Java 對象
          裝載 Spring 的 IOC 框架并創(chuàng)建 Java 對象的步驟

          現(xiàn)在我們將詳細(xì)討論這些步驟:

          1. 當(dāng)初始化 Acegi 應(yīng)用程序時(shí),servlet 容器(本例中為 Apache Tomcat)創(chuàng)建了一個(gè) servlet 上下文,其中保存了有關(guān)應(yīng)用程序資源的信息,例如 JSP 頁面和類。

          2. servlet 容器通知 ContextLoaderListener 類應(yīng)用程序正在啟動(dòng)。

          3. ContextLoaderListener 類創(chuàng)建一個(gè) Web 應(yīng)用程序上下文以保存應(yīng)用程序中特定于 Spring 的資源信息。借助 Spring 的 IOC 框架,您可以裝載自己的自定義應(yīng)用程序上下文。要?jiǎng)?chuàng)建應(yīng)用程序上下文,將使用名為 ContextLoader 的上下文裝載器類裝載應(yīng)用程序上下文。

          4. 如果應(yīng)用程序不需要定義自己的應(yīng)用程序上下文,則可以使用名為 XMLWebApplicationContext 的類,它是 Spring 框架的一部分并提供可處理 Spring XML 配置文件的功能。Acegi 應(yīng)用程序使用的是 Spring 的 XML 配置文件,因此本文僅討論由 XMLWebApplicationContext 類表示的應(yīng)用程序上下文。在本例中,上下文裝載器對 XMLWebApplicationContext 類進(jìn)行實(shí)例化,后者表示您的 Acegi 應(yīng)用程序的應(yīng)用程序上下文。上下文裝載器還在 Web 應(yīng)用程序上下文中設(shè)置 servlet 上下文(于步驟 1 中創(chuàng)建)的引用。

          5. XMLWebApplicationContext 類對 XML 配置文件進(jìn)行解析,獲得關(guān)于 Java 類的信息并將信息裝載到其他內(nèi)部對象中。

          6. XMLWebApplicationContext 類對 XML 配置文件中指定的所有 Java 類進(jìn)行實(shí)例化。XMLWebApplicationContext 類檢查 XML 配置文件中經(jīng)過配置的 Java bean 是否依賴其他的 Java 對象。如果是的話,XMLWebApplicationContext 類將首先對其他 bean 所依賴的 bean 進(jìn)行實(shí)例化。通過這種方式,XMLWebApplicationContext 類創(chuàng)建了 XML 配置文件中定義的所有 bean 的實(shí)例。(注意,步驟 6 假定 XML 配置文件中所有 bean 都不要進(jìn)行保護(hù),稍后一節(jié)將介紹步驟 5 和步驟 6 之間執(zhí)行的額外步驟,從而保護(hù)對此處創(chuàng)建的 Java bean 的訪問)。

          7. XMLWebApplicationContext 類將所有 bean 保存在一個(gè)數(shù)組中。

          您現(xiàn)在已了解到如何從 XML 配置文件中裝載 bean 定義并創(chuàng)建 Java 類的實(shí)例。接下來,我將向您介紹 Spring bean 代理并解釋它對于保護(hù) Java 類實(shí)例的重要性。





          回頁首


          使用 bean 代理

          上一節(jié)討論了 Spring 的 IOC 框架對 Java 對象進(jìn)行實(shí)例化。要保護(hù)對 Java 對象的訪問,Spring 的 IOC 框架使用了 bean 代理 的概念。本節(jié)首先介紹如何配置 bean 代理,然后演示 Spring 的 IOC 框架如何創(chuàng)建代理對象。

          為 Java 對象配置代理

          如果希望創(chuàng)建 bean 代理,Spring IOC 框架要求您對代理創(chuàng)建器 bean 的實(shí)例進(jìn)行配置。Spring 的 IOC 框架使用代理創(chuàng)建器創(chuàng)建代理對象。清單 2 為代理創(chuàng)建器 bean 的配置文件,用于保護(hù)名為 privateCatalog 的 Java 對象:


          清單 2. 代理 bean 配置
                      <bean id="proxyCreator"
                      class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
                      <property name="beanNames">
                      <list>
                      <value>privateCatalog</value>
                      <!--Names of other beans to be proxied -->
                      </list>
                      </property>
                      <property name="interceptorNames">
                      <list>
                      <value>privateCatalogSecurityInterceptor</value>
                      </list>
                      </property>
                      </bean>
                      

          如清單 2 所示,<bean> 標(biāo)記具有一個(gè) class 屬性,其值為 org.springframework.aop.framework.autoproxy. BeanNameAutoProxyCreatorBeanNameAutoProxyCreator 類是 Spring IOC 框架的一部分,可以自動(dòng)創(chuàng)建 bean 代理。Spring 框架提供了 BeanPostProcessor 接口,它提供了一種可擴(kuò)展機(jī)制,允許應(yīng)用程序編寫自己的邏輯來創(chuàng)建 bean 代理。Spring 的 BeanNameAutoProxyCreator 類實(shí)現(xiàn)了 BeanPostProcessor 接口并提供所有必需的代理創(chuàng)建邏輯來保護(hù) Java 類。因此,本文中您無需實(shí)現(xiàn) BeanPostProcessor 接口。

          在創(chuàng)建 bean 代理時(shí),BeanNameAutoProxyCreator 類為所有由 beanNames 屬性定義的 bean 創(chuàng)建代理(參見 清單 2<bean> 標(biāo)記的第一個(gè) <property> 子元素)。beanNames 屬性在 <list> 標(biāo)記中包含一個(gè) bean 名稱列表。在 清單 2 中,我只對希望為之創(chuàng)建代理的 privateCatalog bean進(jìn)行了配置。

          現(xiàn)在查看 清單 2<bean> 標(biāo)記的第二個(gè) <property> 子元素。它指定了名為 interceptorNames 的代理,它將一個(gè)或多個(gè)攔截器的名稱封裝起來。我將在后文詳細(xì)討論攔截器概念。現(xiàn)在,只需了解攔截器可以攔截用戶并在用戶訪問 bean 之前實(shí)現(xiàn)訪問控制策略。

          現(xiàn)在,您已了解了如何對希望進(jìn)行保護(hù)的 bean 配置代理。接下來,您將了解 Spring 的 IOC 框架如何在內(nèi)部為應(yīng)用程序的 bean 創(chuàng)建代理對象。

          Spring IOC 發(fā)揮效用

          在 “使用 Spring 創(chuàng)建 Java 對象” 的步驟 5 和步驟 6 中,您了解了 XMLWebApplicationContext 類如何從 XML 配置文件中讀取 bean 定義并隨后創(chuàng)建 bean 實(shí)例。在創(chuàng)建 bean 實(shí)例之前,XMLWebApplicationContext 類將檢查 XML 配置文件是否包含任何代理創(chuàng)建器 bean(即實(shí)現(xiàn) BeanPostProcessor 接口的 bean)配置。如果存在該 bean,它將要求代理創(chuàng)建器為您希望進(jìn)行保護(hù)的 bean 創(chuàng)建 bean 代理。

          現(xiàn)在考慮代理創(chuàng)建器如何在內(nèi)部創(chuàng)建代理對象:

          1. 代理創(chuàng)建器(即 BeanNameAutoProxyCreator 類)裝載 清單 2 中配置的 beanNames 屬性文件中指定的所有 bean 名稱。

          2. 代理創(chuàng)建器使用 bean 名稱裝載各自的 Java 類,這些類使用了每個(gè) bean 定義的 class 屬性。

          3. 代理創(chuàng)建器創(chuàng)建 清單 2 所示的 interceptorNames 屬性中指定的攔截器的實(shí)例。

          4. 最后,代理創(chuàng)建器創(chuàng)建一個(gè) Cglib2AopProxy 類的實(shí)例,將所有 bean 名稱(步驟 2)和攔截器(步驟 3)傳遞到 Cglib2AopProxy 類。Cglib2AopProxy 類是 Spring 框架的一部分并用于生成動(dòng)態(tài)代理對象。在本例中,Cglib2AopProxy 類將創(chuàng)建安全 bean 訪問控制所需的代理對象。

          Cglib2AopProxy 類實(shí)現(xiàn)了兩個(gè)名為 AOPProxyMethodInterceptor 的接口。AOPProxy 接口由 Spring 框架提供,表示您希望進(jìn)行代理的實(shí)際 bean,因此它與您的 bean 公開相同的方法。MethodInterceptor 接口也源于 AOP 框架,它包含的方法可以在用戶試圖訪問您已執(zhí)行代理的 bean 時(shí)接受控制權(quán)。這意味著 MethodInterceptor 接口處理來自用戶的請求以訪問執(zhí)行過代理的 bean。由于 Cglib2AopProxy 類同時(shí)實(shí)現(xiàn)了 AOPProxyMethodInterceptor 接口,因此它提供了完整的功能,既可以提供經(jīng)過代理的 bean,也可以處理用戶請求以訪問代理 bean(參見 參考資料小節(jié) 中有關(guān) AOP 的討論文章的鏈接)。

          執(zhí)行完前面的步驟后,您現(xiàn)在具有了所需的代理對象。因此 XMLWebApplicationContext 類將安全 bean 的代理(而不是實(shí)際的 bean)保存在 “使用 Spring 創(chuàng)建 Java 對象” 的步驟 7 中的同一個(gè)數(shù)組中。





          回頁首


          訪問執(zhí)行過代理的 Java 對象

          在前面的幾節(jié)中,您了解了 Spring 如何創(chuàng)建公有 bean 和私有 bean。出于本文的目的,您可將公有 bean 視為使用代理保護(hù)的不安全的私有 bean。現(xiàn)在我們來看一下客戶機(jī)應(yīng)用程序?yàn)樵L問公有 bean 和私有 bean 而必須遵循的一系列步驟。

          清單 3 展示了 publicCatalogprivateCatalog 兩個(gè) bean 的 XML 配置。publicCatalog bean 意味著公共訪問,因此不需要使用 bean 代理。privateCatalog bean 意味著只能由指定用戶訪問,因此必須加以保護(hù)。我在清單 3 中包含了 privateCatalog bean 的 bean 代理配置:


          清單 3. publicCatalog 和 privateCatalog bean 的 XML 配置
                      <beans>
                      <bean id="publicCatalog" class="sample.PublicCatalog"/>
                      <bean id="privateCatalog" class="sample.PrivateCatalog"/>
                      <!-- proxy configuration for privateCatalog bean -->
                      <bean id="proxyCreator"
                      class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
                      <property name="beanNames">
                      <list>
                      <value>privateCatalog</value>
                      <!--Names of other beans to be proxied -->
                      </list>
                      </property>
                      <property name="interceptorNames">
                      <list>
                      <value>privateCatalogSecurityInterceptor</value>
                      </list>
                      </property>
                      </bean>
                      <beans>
                      

          應(yīng)用程序可以使用清單 4 中的代碼訪問清單 3 中配置的 publicCatalogprivateCatalog Java bean。注意,清單 4 中顯示的 Java 代碼可位于 JSP 頁面或位于服務(wù)器端 Java 應(yīng)用程序的 bean 中。


          清單 4. 訪問安全和不安全 Java bean 的客戶機(jī)應(yīng)用程序代碼
                      //Step 1: Fetching an instance of the application context
                      XMLWebApplicationContext applicationCtx =
                      WebApplicationContextUtils.getWebApplicationContext(
                      this.getServletConfig().getServletContext());
                      //Step 2: Fetching an insecure bean from the application context
                      PublicCatalog publicCatalog =
                      (PublicCatalog) applicationCtx.getBean("publicCatalog");
                      //Step 3: Calling a method of the insecure bean
                      String publicData = publicCatalog.getData();
                      //Step 4: Fetching a secure bean from the application context
                      PrivateCatalog privateCatalog =
                      (PrivateCatalog) applicationCtx.getBean("privateCatalog");
                      //Step 5: Calling a method of the secure bean
                      String privateData = privateCatalog.getData();
                      

          下面將進(jìn)一步討論清單 4 中的步驟:

          • 步驟 1:取回一個(gè)應(yīng)用程序上下文實(shí)例
            當(dāng)應(yīng)用程序希望訪問 XML 配置文件中配置的 Java bean 時(shí),它必須取回您在 “使用 Spring 創(chuàng)建 Java 對象” 的步驟 4 中見到的 XMLWebApplicationContext 對象。XMLWebApplicationContext 對象包含對 XML 配置文件配置的所有 Java beans 的引用。

          • 步驟 2:從應(yīng)用程序上下文中取回不安全的 bean
            您現(xiàn)在具有一個(gè)對 XMLWebApplicationContext 對象的引用。XMLWebApplicationContext 類公開了一個(gè) getBean() 方法,它包含 bean 的名稱并在數(shù)組中查找 “使用 Spring 創(chuàng)建 Java 對象” 步驟 7 中準(zhǔn)備的 bean。在本例中,該 bean 為 publicCatalog(未執(zhí)行過代理),因此 XMLWebApplicationContext 將返回實(shí)際的 bean。

          • 步驟 3:調(diào)用不安全 bean 的方法
            現(xiàn)在您可以調(diào)用步驟 2 中獲得的 publicCatalog bean 的任何方法。例如,清單 4 顯示的 getData() 方法調(diào)用的執(zhí)行沒有應(yīng)用任何訪問控制并向應(yīng)用程序返回類別數(shù)據(jù)。

          • 步驟 4:從應(yīng)用程序上下文取回安全 bean
            安全 bean 與不安全 bean 的取回方式類似,惟一區(qū)別是:當(dāng)您通過調(diào)用 getBean() 方法嘗試取回安全 bean 時(shí),您將獲得安全對象的代理而不是實(shí)際的對象。該代理就是我在 “Spring IOC 發(fā)揮效用” 步驟 4 中解釋的由 Spring 框架創(chuàng)建的同一個(gè)對象。

          • 步驟 5:調(diào)用安全 bean 的方法
            當(dāng)調(diào)用安全 bean 的方法時(shí),您在 步驟 4 中獲得的代理對象將一個(gè)方法調(diào)用請求分配給攔截器。攔截器將檢查試圖訪問方法的用戶是否具有相應(yīng)的訪問權(quán),從而處理方法調(diào)用請求。

          您現(xiàn)在應(yīng)該對 Spring 框架如何創(chuàng)建 Java 對象以及客戶機(jī)應(yīng)用程序如何與之交互有了清晰的了解。了解了這些內(nèi)容后,就更加容易理解并利用 Acegi 的方法安全性攔截器,下一節(jié)將具體介紹該主題。





          回頁首


          配置 Acegi 的方法安全性攔截器

          只要應(yīng)用程序試圖訪問由 Acegi 安全系統(tǒng)保護(hù)的 bean 方法,請求將被自動(dòng)傳遞到 Acegi 的方法安全性攔截器。方法安全性攔截器的作用就是控制對安全 Java bean 的方法的訪問。攔截器使用 Acegi 的身份驗(yàn)證和授權(quán)框架確認(rèn)用戶是否具有權(quán)利調(diào)用安全 Java bean 的方法,然后相應(yīng)地作出響應(yīng)。

          清單 5 展示 Acegi 的方法安全性攔截器的示例配置:


          清單 5. Acegi 的方法安全性攔截器的示例配置
                      <bean id="privateCatalogSecurityInterceptor"
                      class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
                      <property name="authenticationManager">
                      <ref bean="authenticationManager"/>
                      </property>
                      <property name="accessDecisionManager">
                      <ref bean="accessDecisionManager"/>
                      </property>
                      <property name="objectDefinitionSource">
                      <value>
                      sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING
                      <!-- Roles required by other beans -->
                      </value>
                      </property>
                      </bean>
                      

          清單 5 所示的攔截器配置包含三個(gè)需要進(jìn)行配置的屬性,可以保護(hù)對 Java bean 的訪問:authenticationManageraccessDecisionManagerobjectDefinitionSource

          回憶一下,您在本系列第 1 部分的 配置身份驗(yàn)證處理過濾器 中曾對 authenticationManager 屬性進(jìn)行了配置。authenticationManager 屬性的作用是對用戶進(jìn)行身份驗(yàn)證。

          您在本系列的第二篇文章中了解了 accessDecisionManager 屬性。這個(gè)訪問決策管理器負(fù)責(zé)制定授權(quán)決策。在允許對一個(gè)安全 bean 進(jìn)行訪問之前,方法安全攔截器使用 authenticationManageraccessDecisionManager 屬性對用戶進(jìn)行身份驗(yàn)證和授權(quán)。

          現(xiàn)在查看 清單 5 中配置的 objectDefinitionSource 屬性。它類似于第 1 部分中出現(xiàn)的 objectDefinitionSource 屬性。以前的 objectDefinitionSource 包含類似于 /protected/*/** 這樣的 URL,清單 5 中的 objectDefinitionSource 屬性指定類和方法名;例如,sample.PrivateCatalog 是之前執(zhí)行過代理的類的名稱,而 getData 是您希望對其控制用戶訪問的方法的名字。

          當(dāng)用戶訪問 PrivateCatalog bean 的 getData() 方法時(shí),控制權(quán)將自動(dòng)傳遞給攔截器。攔截器使用 Acegi 框架檢查用戶的業(yè)務(wù)角色是否為 ROLE_HEAD_OF_ENGINEERING(特定于本文的示例)。如果是的話,攔截器將允許對 getData() 方法進(jìn)行訪問。如果攔截器發(fā)現(xiàn)用戶角色不是 ROLE_HEAD_OF_ENGINEERING,則拒絕訪問。

          下一節(jié)將查看一個(gè)示例 Acegi 應(yīng)用程序,它將實(shí)現(xiàn)您目前所了解的所有概念。





          回頁首


          示例 Acegi 應(yīng)用程序

          本文的 下載源代碼 包含了一個(gè)名為 AcegiMethodSecurity 的示例應(yīng)用程序,可按照以下方法進(jìn)行配置和部署:

          1. 使用用戶信息填充 LDAP 服務(wù)器。下載的示例應(yīng)用程序 包含一個(gè) LDIF 文件,其中含有預(yù)備裝載到 LDAP 服務(wù)器的用戶信息。關(guān)于如何將 LDIF 文件導(dǎo)入到 LDAP 服務(wù)器,請參考第 2 部分的 “填充服務(wù)器” 一節(jié)。注意,該應(yīng)用程序涉及與第 2 部分相同的用戶(alicebobspecialUser)。

          2. 將本文下載源代碼中的 acegiMethodSecurity.war 文件復(fù)制到 Tomcat 安裝目錄中的 webapps 目錄。

          3. 將 Acegi 的 jar 文件復(fù)制到示例應(yīng)用程序的 WEB-INF/lib 文件夾。(有關(guān)內(nèi)容請參考第 1 部分的 “部署和運(yùn)行應(yīng)用程序” 一節(jié)。 )

          4. 下載 cglib-full-2.0.2.jar 文件并將其復(fù)制到示例應(yīng)用程序的 WEB-INF/lib 文件夾。

          啟動(dòng) Tomcat 并嘗試運(yùn)行示例應(yīng)用程序。

          運(yùn)行示例應(yīng)用程序

          通過從瀏覽器訪問 http://localhost:8080/acegiMethodSecurity URL 可調(diào)用示例應(yīng)用程序。AcegiMethodSecurity 顯示的索引頁面包含兩個(gè)鏈接(CatalogLogin),如圖 2 所示:


          圖 2. 示例應(yīng)用程序的主頁面
          示例應(yīng)用程序的主頁面

          當(dāng)單擊應(yīng)用程序的 Catalog 鏈接時(shí),它將要求您進(jìn)行登錄。如果以 alicespecialUser 的身份進(jìn)行登錄,示例應(yīng)用程序?qū)⑻峁?em>完整的 類別,包括公有數(shù)據(jù)和私有數(shù)據(jù)。這是因?yàn)樵?清單 5 中,您對方法安全性攔截器進(jìn)行了配置,允許用戶使用 ROLE_HEAD_OF_ENGINEERING 訪問私有類別,而 alicespecialUser 都具有該訪問權(quán)。另一方面,如果您以 bob 的身份登錄,示例應(yīng)用程序?qū)H顯示公有數(shù)據(jù)。





          回頁首


          為通過身份驗(yàn)證的用戶分配額外角色

          本節(jié)將演示經(jīng)過增強(qiáng)的示例應(yīng)用程序。增強(qiáng)后的示例應(yīng)用程序?qū)⒄故?Acegi 如何使您能夠在運(yùn)行時(shí)向通過身份驗(yàn)證的用戶臨時(shí)分配額外角色。

          當(dāng)安全 bean(例如 清單 3privateCatalog bean)要訪問一個(gè)原創(chuàng)資源時(shí),您可能需要使用額外的角色。例如,您可能考慮到您的安全 bean 需要通過 Java 的 Remote Method Invocation (RMI) 框架或一個(gè) Web 服務(wù)訪問某個(gè)遠(yuǎn)程應(yīng)用程序。訪問安全 bean 的用戶不會(huì)占用遠(yuǎn)程應(yīng)用程序要求訪問用戶所具備的業(yè)務(wù)角色。

          在本例中,Acegi 首先檢查用戶是否經(jīng)過授權(quán)來訪問安全 bean。之后,Acegi 允許用戶訪問安全 bean。當(dāng)安全 bean 試圖訪問遠(yuǎn)程服務(wù)時(shí),它需要使用額外的業(yè)務(wù)角色。如果訪問安全 bean 的用戶不具備額外角色,安全 bean 就不能成功訪問遠(yuǎn)程服務(wù)。

          run-as-replacement 機(jī)制

          Acegi 框架提供了一種名為 run-as-replacement 的簡單機(jī)制,允許您僅在方法調(diào)用期間為通過身份驗(yàn)證的用戶配置一個(gè)或多個(gè)額外角色。您可以使用 run-as-replacement 機(jī)制為訪問遠(yuǎn)程應(yīng)用程序的安全 bean 配置額外角色。這意味著只要安全 bean 需要訪問遠(yuǎn)程應(yīng)用程序,Acegi 將為用戶裝載額外角色,從而允許安全 bean 訪問遠(yuǎn)程應(yīng)用程序。

          清單 6 對 清單 5 中的方法安全性攔截器的配置進(jìn)行了增強(qiáng)。增強(qiáng)后的配置使用了 run-as-replacement 機(jī)制。


          清單 6. Acegi 方法安全性攔截器的增強(qiáng)配置
                      <bean id="privateCatalogSecurityInterceptor"
                      class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
                      <property name="authenticationManager">
                      <ref bean="authenticationManager"/>
                      </property>
                      <property name="accessDecisionManager">
                      <ref bean="accessDecisionManager"/>
                      </property>
                      <property name="runAsManager">
                      
          <bean id="runAsManager" class="org.acegisecurity.runas.RunAsManagerImpl">
          <property name="key"> <value>myKeyPass</value> </property> </bean> </property> <property name="objectDefinitionSource"> <value> sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING,RUN_AS_MANAGER </value> </property> </bean>

          清單 6 使用粗體顯示了兩處增強(qiáng)(與 清單 5 相比)。第一處增強(qiáng)為 runAsManager 屬性。runAsManager 屬性的作用是向通過身份驗(yàn)證的用戶動(dòng)態(tài)添加角色。出于這個(gè)目的,runAsManager 屬性包含了 RunAsManagerImpl bean 的定義。RunAsManagerImpl bean 只有在滿足下面的條件時(shí)才可變?yōu)榛钴S狀態(tài):在 objectDefinitionSource 方法的角色定義中找到以 RUN_AS_ 為前綴的角色。例如,PrivateCatalog.getData() 方法的角色定義(清單 6 中以粗體顯示的第二處增強(qiáng))具有一個(gè) RUN_AS_MANAGER 角色。

          RunAsManagerImpl bean 包含一個(gè)名為 key 的屬性,它封裝的加密鍵用于確保只將額外的角色作為 run-as-replacement 程序的一部分生成。

          當(dāng)用戶調(diào)用 getData() 方法時(shí),RunAsManagerImpl bean 變?yōu)榛钴S狀態(tài)并創(chuàng)建名為 RUN_AS_MANAGER 的額外角色,從而啟用 getData() 方法訪問遠(yuǎn)程應(yīng)用程序。

          增強(qiáng)的方法安全性

          本文的 下載源代碼 包含一個(gè)名為 EnhancedAcegiMethodSecurity 的示例應(yīng)用程序,它可以演示 run-as-replacement 機(jī)制和程序。該應(yīng)用程序?qū)@示一個(gè)具有 Catalog 鏈接的索引頁面。如果單擊 Catalog 鏈接,將要求進(jìn)行登錄。

          登錄后,EnhancedAcegiMethodSecurity 應(yīng)用程序?qū)槟峁┑卿浻脩艏捌浣巧耐暾畔ⅰ@纾绻?alicespecialUser 身份登錄,將向您顯示用戶的所有業(yè)務(wù)角色,包括額外創(chuàng)建的臨時(shí)的 RUN_AS_MANAGER 角色。

          結(jié)束語

          在這份共分三部分的系列文章中,我介紹了如何使用 Acegi 安全系統(tǒng)增強(qiáng)基于 URL 的安全性和基于方法的安全性。您了解了如何設(shè)計(jì)訪問控制策略并將它們托管在目錄服務(wù)器中,如何對 Acegi 進(jìn)行配置以與目錄服務(wù)器進(jìn)行通信,以及如何根據(jù)托管在服務(wù)器的訪問控制策略制定身份驗(yàn)證和授權(quán)決策。

          本系列的最后一篇文章主要介紹使用基于方法的安全性保護(hù) Java 類實(shí)例。文章還解釋了 Acegi 和 Spring 如何在內(nèi)部創(chuàng)建和代理 Java 對象以及 bean 代理如何實(shí)現(xiàn)訪問控制。文章包含了兩個(gè)示例應(yīng)用程序,您可以使用它們進(jìn)一步研究本系列中學(xué)到的概念,更多有關(guān)使用 Acegi 保護(hù) Java 應(yīng)用程序的內(nèi)容,請參見 參考資料 小節(jié)。



          來自:http://www-128.ibm.com/developerworks/cn/java/j-acegi3/?

          posted on 2008-05-08 18:47 狼愛上貍 閱讀(418) 評論(0)  編輯  收藏 所屬分類: Acegi

          主站蜘蛛池模板: 鄯善县| 化德县| 惠水县| 香港 | 丁青县| 东安县| 上虞市| 宣威市| 泽库县| 昭通市| 海晏县| 中宁县| 日土县| 沧源| 商南县| 姚安县| 金沙县| 云阳县| 南川市| 溆浦县| 镇江市| 潞城市| 嵩明县| 四会市| 太康县| 集贤县| 连山| 崇义县| 山东| 孝昌县| 宁晋县| 武夷山市| 博乐市| 武城县| 偏关县| 邵阳市| 宁强县| 温泉县| 鄂温| 武清区| 承德市|