<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    szhswl
    宋針還的個(gè)人空間

    本文檔是"Spring框架下Acegi安全系統(tǒng)"(Acegi Security System for Spring)的一份參考指南,Acegi安全系統(tǒng)是由一序列類(lèi)構(gòu)成,這些類(lèi)為Spring框架提供認(rèn)證和授權(quán)服務(wù)。
    我得感謝這份參考在Spring框架中用DocBook配置進(jìn)行了精心的包裝。Spring小組在他們的DocBook中對(duì)Chris Bauer (Hibernate)的幫助表示感謝。

    第一章 安全

    1.1 準(zhǔn)備

    為了安全使用Acegi,Acegi的每一個(gè)正式發(fā)布的JAR都署上了一個(gè)項(xiàng)目前導(dǎo)字符.這不表示對(duì)受權(quán)書(shū)中的免責(zé)聲明有任何的改變,但它確保你能使用一個(gè)適當(dāng)?shù)慕?jīng)過(guò)檢查的正式構(gòu)建的Acegi安全系統(tǒng).有關(guān)怎樣驗(yàn)證JAR文件是否正確地簽署以及哪些證書(shū)用來(lái)對(duì)他們進(jìn)行認(rèn)證的說(shuō)明請(qǐng)參考在發(fā)布版本中根目錄下的readme.txt文件.

    1.2介紹

    Acegi通過(guò)對(duì)流行的WEB容器的可選集成而為使用Spring編寫(xiě)的項(xiàng)目提供認(rèn)證與授權(quán)的能力.這種安全架構(gòu)是全部用"Spring方式"開(kāi)發(fā),包括使用bean contexts、攔截器和接口驅(qū)動(dòng)的編程方式。結(jié)果,對(duì)那些為基于Spring應(yīng)用的尋求安全保證應(yīng)用來(lái)說(shuō),Acegi是一個(gè)非常有用的外置式的安全架構(gòu),它很容易適用于各種復(fù)機(jī)的用戶(hù)化需求。

    安全系統(tǒng)保括兩個(gè)顯而易見(jiàn)的方面:認(rèn)證和授權(quán)。前者解決調(diào)用者是否是他們所聲稱(chēng)的人的問(wèn)題,而授權(quán)則是關(guān)于已經(jīng)經(jīng)過(guò)認(rèn)證的調(diào)用者是否允許進(jìn)行給定操作的問(wèn)題。

    在Acegi中,需要認(rèn)證的用戶(hù)、系統(tǒng)或都代理都作為一個(gè)"參與者"來(lái)題及。這個(gè)安全架構(gòu)沒(méi)有你在其它安全系統(tǒng)是所熟悉的角色或組的概念,即使Acegi完全提供相應(yīng)的功能。

    1.2.1 發(fā)布號(hào)

    理解Acegi的發(fā)布號(hào)的含意是有用的,因?yàn)樗鼘⒂兄谧C實(shí)你已經(jīng)(或者還沒(méi)將它)升級(jí)到這個(gè)項(xiàng)目的未來(lái)版本的。正式地,我們使用"Apache Portable Runtime Project"版本號(hào)使作指南,你可以在http://apr.apache.org/versioning.html中看到。為方便起見(jiàn),我們引用了那頁(yè)中的介紹。

    "版本號(hào)使用標(biāo)準(zhǔn)的三個(gè)一組的整數(shù)來(lái)表示:主版本號(hào).次版本號(hào).補(bǔ)丁號(hào)。主版本號(hào)表示API不兼容和對(duì)它進(jìn)行了大型升級(jí)。次版本號(hào)表示與之前的舊的較小的版本在源代碼和二進(jìn)制代碼上保持兼容性。補(bǔ)丁級(jí)版本號(hào)的改變表示無(wú)論向前向后完全兼容。

    1.3 系統(tǒng)設(shè)計(jì)

    1.3.1 關(guān)鍵組件

    大多數(shù)企業(yè)級(jí)的應(yīng)用有四個(gè)基本安全需求。首先,他們要能夠認(rèn)證一個(gè)訪問(wèn)者;其次,他們需要有能力對(duì)web請(qǐng)求提供安全保證;第三,企業(yè)級(jí)應(yīng)用需要有能力對(duì)服務(wù)層方法提供安全保證;最后,企業(yè)級(jí)應(yīng)用經(jīng)常要有能力對(duì)域?qū)ο髮?shí)例提供安全保護(hù)。Acegi提供了一個(gè)通用的框架,來(lái)滿(mǎn)足所有這四個(gè)通用的企業(yè)級(jí)應(yīng)用安全需求。

    Acegi基本上由八個(gè)關(guān)鍵功能部分組成。

    Authentication對(duì)象 它包括參與者、認(rèn)證證書(shū)和賦予參與者的權(quán)限。這個(gè)對(duì)象也能存儲(chǔ)一些與認(rèn)證請(qǐng)求有關(guān)的附加信息。例如源TCP/IP地址.
    SecurityContextHolder對(duì)象 它包含一個(gè)在線程級(jí)對(duì)象內(nèi)的Authentication 認(rèn)證對(duì)象
    AuthenticationManager對(duì)象 它鑒別由ContextHolder引進(jìn)的Authentication對(duì)象.
    AccessDecisionManager對(duì)象 授權(quán)一個(gè)給定的操作。
    RunAsManager對(duì)象 當(dāng)一個(gè)給定的操作被執(zhí)行時(shí),任意替代Authentication 對(duì)象
    "安全對(duì)象"攔截器 配合認(rèn)證、授權(quán)、run-as替換,從而調(diào)用處理執(zhí)行給定的操作。
    AfterInvocationManager對(duì)象 能夠修改一個(gè)從"安全對(duì)象"調(diào)用中返的對(duì)象。例如刪去一些參與者沒(méi)有授權(quán)存取的集合元素。
    存取控制列表(ACL)管理包 用于獲取應(yīng)用于域?qū)ο髮?shí)例ACLs。

    "安全對(duì)象"攔截器執(zhí)行Acegi安全系統(tǒng)中的大多數(shù)關(guān)鍵類(lèi)。這樣做是為了利用框架的主要特性。

    由于它的重要性,圖1表示了AbstractSecurityInterceptor 攔截器類(lèi)的主要關(guān)系和具體實(shí)現(xiàn)。
    500)this.width=500" align=absMiddle border=0>

    每個(gè)"安全對(duì)象"攔截器(下文中稱(chēng)為"保護(hù)性攔截器")作用于一個(gè)特殊類(lèi)型的"安全對(duì)象"。那么,什么是安全對(duì)象?安全對(duì)象是指對(duì)它采取了安全保護(hù)措施的任何類(lèi)型的對(duì)象。一個(gè)安全對(duì)象必須提供某種形式回調(diào),這樣當(dāng)需要的時(shí)候保護(hù)性攔截器就能明顯地起作用。保護(hù)性攔截器回調(diào)對(duì)象同時(shí)繼續(xù)所請(qǐng)求的操作。如果安全對(duì)象不能提供一個(gè)本地的回調(diào)方法,就要寫(xiě)一個(gè)包裝器來(lái)實(shí)現(xiàn)它。

    每個(gè)安全對(duì)象都有一個(gè)實(shí)現(xiàn)它的包放在org.acegisecurity.intercept包中。在安全系統(tǒng)中的每個(gè)其它包是一個(gè)獨(dú)立的安全對(duì)象.因此它能支持上述的任何一種安全對(duì)象.

    只有那些想對(duì)攔截和認(rèn)證請(qǐng)求采用全新方法的開(kāi)發(fā)者才需要直接使用安全對(duì)象.例如有可能建立一個(gè)新的安全對(duì)象來(lái)對(duì)沒(méi)有使用 MethodInvocations 對(duì)象的消息系統(tǒng)提供安全保護(hù).大多數(shù)的Spring應(yīng)用將簡(jiǎn)單地完全透明地使用三種普遍支持安全對(duì)象類(lèi)型 ((AOP Alliance MethodInvocation, AspectJ 連接點(diǎn) 和 web 請(qǐng)求過(guò)濾攔截器)

    Acegi安全系統(tǒng)中八個(gè)關(guān)鍵部分的每個(gè)部分都將在本文中詳細(xì)討論.

    1.3.2 所支持的安全對(duì)象

    如圖1所示,目前Acegi安全系統(tǒng)支持三種安全對(duì)象.
    第一種對(duì)象處理AOP Alliance MethodInvocation.這種安全對(duì)象用于保護(hù)Spring Bean.開(kāi)發(fā)者通常用它來(lái)保護(hù)他們的業(yè)務(wù)對(duì)象.為了生成一個(gè)標(biāo)準(zhǔn)的Spring-hosted類(lèi)型的bean 用作MethodInvocation,Bean簡(jiǎn)單地通過(guò) ProxyFactoryBean 或者 BeanNameAutoProxyCreator 或者 DefaultAdvisorAutoProxyCreator來(lái)公布.大多數(shù)Spring開(kāi)發(fā)者對(duì)此都已很熟悉,因?yàn)樗麄兪褂眠^(guò)Spring的事務(wù)處理和Spring的其它方面.

    第二種對(duì)象是AspectJ連接點(diǎn)對(duì)象.AspectJ在域?qū)ο髮?shí)例安全方面有一種特殊的應(yīng)用,這通常是在 Spring bean容器之外.通過(guò)使用AspectJ,利用標(biāo)準(zhǔn)的構(gòu)造函數(shù),如new Person(),Acegi 安全系統(tǒng)對(duì)他們提供安全保護(hù). AspectJSecurityInterceptor仍然由Spring管理.它創(chuàng)建Aspect單例,并通過(guò)適當(dāng)?shù)恼J(rèn)證管理器、存取判別管理器等將它聯(lián)系起來(lái)。

    第三種是過(guò)濾器調(diào)用(FilterInvocation)對(duì)象.它包含在Acegi安全系統(tǒng)內(nèi)。它由一個(gè)包含的過(guò)濾器創(chuàng)建并簡(jiǎn)單地封裝了HTTP ServletRequest、ServletResponse和FilterChain 。過(guò)濾器調(diào)用對(duì)象對(duì)HTTP資源提供了安全保護(hù)。開(kāi)發(fā)者通常不需要了解它的工作機(jī)制,因?yàn)樗麄冎灰谒麄兊膚eb.xml中添加過(guò)濾器來(lái)讓安全系統(tǒng)工作。

    1.3.3配置屬性

    每一個(gè)安全對(duì)象都能作用于一些特殊的請(qǐng)求。例如,MethodInvocation能用于對(duì)帶有任意參數(shù)的任何方的的調(diào)用。而FilterInvocation能用在任何的HTTP URL上。

    Acegi 安全系統(tǒng)需要記錄一些配置信息,這些配置信息用于各種可能的請(qǐng)求。例如BankManager.getBalance (int accountNumber)請(qǐng)求所需的安全配置與BankManager.approveLoan (int applicationNumber)請(qǐng)求所需的安全配置有很大的不同。與此類(lèi)似,http://some.bank.com/index.htm請(qǐng)求所需的安全配置與http://some.bank.com/manage/timesheet.jsp請(qǐng)求所需的安全配置也有很大的不同。

    為了存儲(chǔ)針對(duì)各種不同請(qǐng)求的各種安全配置,就要使用配置屬性。在實(shí)現(xiàn)上配置屬性通過(guò)ConfigAttribute接口來(lái)表示。SecurityConfig是ConfigAttribute接口的一個(gè)具體實(shí)現(xiàn),它簡(jiǎn)單地把配置屬性當(dāng)作一個(gè)串(String)來(lái)存儲(chǔ)。

    與特定請(qǐng)求相聯(lián)系的ConfigAttributes 集合保存在ConfigAttributeDefinition中。這個(gè)類(lèi)只是一個(gè)簡(jiǎn)單的ConfigAttributes存儲(chǔ)器,并不做其它特別的處理。

    當(dāng)安全性攔截器收到一個(gè)請(qǐng)求時(shí),它需要判斷使用哪些配置屬性。換句話說(shuō),它需要找到用于這種請(qǐng)求的 ConfigAttributeDefinition.這種判別是通過(guò)ObjectDefinitionSource接口來(lái)處理的.這個(gè)接口提供的主要方法是 public ConfigAttributeDefinition getAttributes(Object object),其中的Object 就是要保護(hù)的安全對(duì)象。因?yàn)榘踩珜?duì)象包含了請(qǐng)求的細(xì)節(jié),所以O(shè)bjectDefinitionSource實(shí)現(xiàn)類(lèi)將能夠抽取它所需要的細(xì)節(jié)來(lái)檢查相關(guān)的 ConfigAttributeDefinition.

    1.4 Request Contexts

    1.4.1以前的方式

    Acegi 安全系統(tǒng)在發(fā)布0.9.0以前,使用ContextHolder來(lái)存儲(chǔ)session間的上下文信息(Context).Context的一個(gè)特殊子類(lèi), SecureContext定義了一個(gè)接口來(lái)存儲(chǔ)認(rèn)證對(duì)象(Authentication object).ContextHolder是一個(gè)線程 (ThreadLocal)類(lèi)型的對(duì)象,有關(guān)Acegi安全系統(tǒng)中線程類(lèi)對(duì)象用法的更全面的討論將放在本文的后續(xù)章節(jié)中.為了保持一致,經(jīng)過(guò)與其它 Spring開(kāi)發(fā)者討論,從0.9.0開(kāi)始,我們將移去ContextHolder和SecureContext.有關(guān)詳情請(qǐng)參考http://article.gmane.org/gmane.comp.java.springframework.devel/8290 和JIRA task SEC-77.這段歷史之所以被提及是因?yàn)镃ontextHolder使用了很長(zhǎng)一段時(shí)間,你所遇到某些有關(guān)Acegi安全系統(tǒng)的文檔可能仍舊說(shuō)到了 ContextHolder.通常你可以用SecurityContextHolder替代ContextHolder,用 SecurityContext替代SecureContext,這樣你就能了解這些文檔的主要意思.

    1.4.2 SecurityContext

    Acegi 安全系統(tǒng)用SecurityContextHolder來(lái)存儲(chǔ)SecurityContext.SecurityContext包含有 Authentication的getter/setter方法.為了獲得當(dāng)前SecurityContext(或者參與者),所有Acegi安全類(lèi)都要查詢(xún)SecurityContextHolder.SecurityContextHolder是一個(gè)線程,這意味著它與當(dāng)前線程的執(zhí)行有關(guān).

    1.4.3 Context Storage

    Acegi安全系統(tǒng)設(shè)計(jì)的重點(diǎn)就是在兩個(gè)web請(qǐng)求之間存儲(chǔ)SecurityContextHolder(它是SecurityContext的實(shí)現(xiàn)類(lèi))的內(nèi)容.通過(guò)SecurityContextHolder獲取存儲(chǔ)在SecurityContext內(nèi)Authentication,這樣成功認(rèn)證的參與者就能在隨后的請(qǐng)求中鑒別到.HttpSessionContextIntegrationFilter一直存在到自動(dòng)拷貝一個(gè)定義好 HttpSession屬性的內(nèi)容到SecurityContextHolder中,然后,在每一個(gè)請(qǐng)求的結(jié)尾,再將 SecurityContextHolder的內(nèi)容拷貝回為下一個(gè)請(qǐng)求準(zhǔn)備的HttpSession中.

    將HttpSessionContextIntegrationFilter放在其它任何 Acegi安全過(guò)濾器之前(沒(méi)有這樣做是終端用戶(hù)很容易犯的一個(gè)共同的錯(cuò)誤)是必須的.當(dāng)覺(jué)得合適時(shí),Acegi安全過(guò)濾器期望能夠修改 SecurityContextHolder的內(nèi)容,并且如果有必要其它的類(lèi)(也就是 HttpSessionContextIntegrationFilter)將在請(qǐng)求之間存儲(chǔ)這些信息.這就是為什么 HttpSessionContextIntegrationFilter必須是第一個(gè)被用的過(guò)濾器.

    通過(guò)設(shè)置HttpSessionContextIntegrationFilter bean中的context屬性,你能定義一個(gè)特定的SecurityContext實(shí)現(xiàn)類(lèi)用到你的應(yīng)用中.

    1.4.4 本地化

    從1.0.0 開(kāi)始,Acegi安全系統(tǒng)支持異常消息的本地化,這是終端用戶(hù)很希望看到的特性.例如認(rèn)證失敗和存取被否定(授權(quán)失敗)異常的本地化.那些面向開(kāi)發(fā)者或系統(tǒng)配置員的異常和日志(包括不正確的屬性、接口約定違背、使用不正確的構(gòu)造函數(shù)、啟動(dòng)時(shí)間確認(rèn)、調(diào)試級(jí)的日志)等沒(méi)有本地化,而是用英語(yǔ)硬編碼在 Acegi安全系統(tǒng)的代碼內(nèi).

    在org.acegisecurity包內(nèi)裝載的acegi-security-xx.jar是一個(gè) messages.properties文件。當(dāng)Acegi安全類(lèi)實(shí)現(xiàn)Spring的MessageSourceAware接口,并且希望消息解析器在應(yīng)用上下文啟動(dòng)時(shí)被依賴(lài)注入時(shí),它就會(huì)用到。通常你所需要做的只是在你的應(yīng)用上下文中注冊(cè)一個(gè)bean來(lái)指向這些消息。下面是一個(gè)示例。

    <bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename"><value>org/acegisecurity/messages</value></property>
    </bean>

    messages.properties 文件的命名符合標(biāo)準(zhǔn)資源約束,用Acegi安全消息支持的默認(rèn)的語(yǔ)言來(lái)表示并在上述的bean定義中注冊(cè)它。在這個(gè)文件內(nèi)沒(méi)有許多的消息關(guān)鍵詞,因此本地化不應(yīng)認(rèn)為是一個(gè)主要的問(wèn)題。如果你打算對(duì)這個(gè)文件進(jìn)行本地化,請(qǐng)考慮登記一個(gè)JIRA任務(wù)與社區(qū)共享你的工作,并為 messages.properties文件的本地化版本附上一個(gè)適當(dāng)?shù)拿帧?/p>

    有關(guān)本地化的討論是一個(gè)叫 org.springframework.context.i18n.LocaleContextHolder的Spring 線程,Acegi通過(guò)使用 Locale來(lái)獲得這個(gè)線程,從而對(duì)一個(gè)消息源中的消息實(shí)行本地化。Spring文檔為你提供了有關(guān)使用LocaleContextHoldert和能自動(dòng)設(shè)置它的幫助類(lèi)(如AcceptHeaderLocaleResolver, CookieLocaleResolver, FixedLocaleResolver, SessionLocaleResolver 等)的更詳細(xì)的情況.

    1.5 安全性攔截

    1.5.1所有的安全對(duì)象

    如在系統(tǒng)設(shè)計(jì)部分描述的那樣,每一個(gè)安全對(duì)象都有它自己的安全性攔截器來(lái)負(fù)責(zé)處理每一個(gè)請(qǐng)求

    處理過(guò)程包括以下這些操作:
    1. 存儲(chǔ)每一個(gè)安全請(qǐng)求的配置屬性。
    2. 從相應(yīng)的ObjectDefinitionSource提取 ConfigAttributeDefinition應(yīng)用到請(qǐng)求中。
    3. 從SecurityContext中獲取Authentication對(duì)象,這個(gè)對(duì)象保存在SecurityContextHolder中。
    4. 傳遞Authentication對(duì)象到AuthenticationManager中,通過(guò)響應(yīng)更新SecurityContextHolder。
    5. 傳遞Authentication 對(duì)象、ConfigAttributeDefinition和安全對(duì)象到AccessDecisionManager中。
    6. 傳遞Authentication 對(duì)象、ConfigAttributeDefinition和安全對(duì)象到RunAsManager中。
    7. 如果RunAsManager對(duì)象返回一個(gè)新的Authentication 對(duì)象,就用它更新SecurityContextHolder對(duì)象。
    8. 繼續(xù)執(zhí)行安全對(duì)象的請(qǐng)求。
    9. 如果上一步中RunAsManager對(duì)象返回一個(gè)新的Authentication對(duì)象,就用它更新以前從AuthenticationManager中返回的SecurityContextHolder對(duì)象。
    10. 如果定義了AfterInvocationManager,把安全對(duì)象的執(zhí)行結(jié)果傳遞給它。從而它可以拋出AccessDeniedException異常,接受可能需要的返回對(duì)象。
    11. 返回從AfterInvocationManager處收到的任何結(jié)果,或如沒(méi)定義AfterInvocationManager,就返回一個(gè)安全對(duì)象執(zhí)行后提供的簡(jiǎn)單結(jié)果。

    雖然看起來(lái)有點(diǎn)麻煩,但別擔(dān)心;開(kāi)發(fā)者與安全處理的交互只是簡(jiǎn)單地使用幾個(gè)基本的接口(如AccessDecisionManager)實(shí)現(xiàn)來(lái)完成的。下面我們將詳細(xì)的討論它們。

    AbstractSecurityInterceptor處理了上述過(guò)程的大部分。如圖一所示,每個(gè)安全對(duì)象都有它自已的安全性攔截器,它們是AbstractSecurityInterceptor的子類(lèi)。這些安全對(duì)象--具體的安全性攔截器都將在下面詳細(xì)討論。

    1.5.2 AOP Alliance(MethodInvocation)安全性攔截器

    為了對(duì)MethodInvocations對(duì)象提供保護(hù),開(kāi)發(fā)者只需要簡(jiǎn)單地加上恰當(dāng)配置的方法安全性攔截器(MethodSecurityInterceptor)到你的應(yīng)用中,然后將需要查詢(xún)的bean鏈接到攔截器鏈中去。這種鏈接方法由Spring的 ProxyFactoryBean或BeanNameAutoProxyCreator來(lái)完成,就如Spring的許多其它部分的用法(請(qǐng)參考應(yīng)用實(shí)例)一樣,另外,Acegi安全系統(tǒng)也提供一個(gè)MethodDefinitionSourceAdvisor,它將使用Spring的 DefaultAdvisorAutoProxyCreator自動(dòng)鏈接MethodSecurityInterceptor之前的任何bean到這個(gè)安全性攔截器;MethodSecurityInterceptor本身定義如下:

    <bean id="bankManagerSecurity"
    class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
    <property name="validateConfigAttributes"><value>true</value></property>
    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
    <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
    <property name="runAsManager"><ref bean="runAsManager"/></property>
    <property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property>
    <property name="objectDefinitionSource">
    <value>
    org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
    org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
    </value>
    </property>
    </bean>

    如上所示MethodSecurityInterceptor配置了三個(gè)引用:AuthenticationManager, AccessDecisionManager和RunAsManager。下面我們將分節(jié)討論它們。在這個(gè)例子中我們將定義 AfterInvocationManager,雖然它是可選的。MethodSecurityInterceptor也是通過(guò)"配置屬性"來(lái)配置的,這些配置屬性用于不同的方法簽名。有關(guān)配置屬性的全面的論述已在本文的系統(tǒng)設(shè)計(jì)部分提供。

    MethodSecurityInterceptor 有三種通過(guò)配置屬性來(lái)配置的方法,第一種是經(jīng)由屬性編輯器和應(yīng)用上下文,如上所示。第二種使用Jakarta Commons Attributes或 Java 5 Annotation在你的源代碼中通過(guò)定義配置屬性來(lái)配置。第三種方法是你自己寫(xiě)一個(gè)ObjectDefinitionSource,雖然這已超出本文檔的范圍。

    不管使用哪種方法,ObjectDefinitionSource都會(huì)相應(yīng)地返回一個(gè)ConfigAttributeDefinition對(duì)象,ConfigAttributeDefinition對(duì)象含有一個(gè)單獨(dú)的安全方法的所有配置屬性。

    應(yīng)用注意:MethodSecurityInterceptor.setObjectDefinitionSource()方法實(shí)際需要一個(gè) MethodDefinitionSource實(shí)例,這是一個(gè)標(biāo)志性接口,是ObjectDefinitionSource的一個(gè)子類(lèi)。它簡(jiǎn)單地指示 ObjectDefinitionSource認(rèn)到MethodInvocations。為了簡(jiǎn)單起見(jiàn),我們將繼續(xù)把 MethodDefinitionSource當(dāng)作ObjectDefinitionSource,因?yàn)閷?duì)大多數(shù)使用 MethodSecurityInterceptor用戶(hù)來(lái)說(shuō),區(qū)別很小。

    如果使用應(yīng)用上下文屬性編輯器方法(如上所示),要使用逗號(hào)來(lái)區(qū)隔不同應(yīng)用于給定方法模式的配置屬性.每一個(gè)配置屬性都將賦值到它們本身的SecurityConfig對(duì)象中去.SecurityConfig對(duì)象已在系統(tǒng)設(shè)計(jì)部分討論.

    如果你使用Jakarta Commons Attributes方式,你的bean上下文配置將會(huì)是不同的,如下所示:

    <bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>
    <bean id="objectDefinitionSource"
    class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
    <property name="attributes"><ref local="attributes"/></property>
    </bean>
    <bean id="bankManagerSecurity"
    class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
    <property name="validateConfigAttributes"><value>false</value></property>
    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
    <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
    <property name="runAsManager"><ref bean="runAsManager"/></property>
    <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property>
    </bean>

    另外,你的源代碼將包含akarta Commons Attributes的tag標(biāo)記.用它來(lái)指示ConfigAttribute的一個(gè)具體實(shí)現(xiàn).
    下面這個(gè)例子使用SecurityConfig實(shí)現(xiàn)來(lái)表示配置屬性,其結(jié)果與上面用屬性編緝器方式的安全配置一樣.

    public interface BankManager {
    /**
    * @@SecurityConfig("ROLE_SUPERVISOR")
    * @@SecurityConfig("RUN_AS_SERVER")
    */
    public void deleteSomething(int id);
    /**
    * @@SecurityConfig("ROLE_SUPERVISOR")
    * @@SecurityConfig("RUN_AS_SERVER")
    */
    public void deleteAnother(int id);
    /**
    * @@SecurityConfig("ROLE_TELLER")
    * @@SecurityConfig("ROLE_SUPERVISOR")
    * @@SecurityConfig("BANKSECURITY_CUSTOMER")
    * @@SecurityConfig("RUN_AS_SERVER")
    */
    public float getBalance(int id);
    }

    如果你使用Spring Security Java 5 Annotations方式,你的bean上下文配置如下所示:

    <bean id="attributes" class="org.acegisecurity.annotation.SecurityAnnotationAttributes"/>
    <bean id="objectDefinitionSource"
    class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
    <property name="attributes"><ref local="attributes"/></property>
    </bean>
    <bean id="bankManagerSecurity"
    class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
    <property name="validateConfigAttributes"><value>false</value></property>
    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
    <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
    <property name="runAsManager"><ref bean="runAsManager"/></property>
    <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property>
    </bean>

    另外,你的源代碼將包含Acegi Java 5 Security Annotations,用它來(lái)表示ConfigAttribute,下面的例子使用@Secured注釋來(lái)表示配置屬性.其結(jié)果與上面用屬性編緝器方式的安全配置相同.

    import org.acegisecurity.annotation.Secured;
    public interface BankManager {
    /**
    * Delete something
    */
    @Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" })
    public void deleteSomething(int id);
    /**
    * Delete another
    */
    @Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" })
    public void deleteAnother(int id);
    /**
    * Get balance
    */
    @Secured({"ROLE_TELLER","ROLE_SUPERVISOR","BANKSECURITY_CUSTOMER","RUN_AS_SERVER" })
    public float getBalance(int id);
    }

    也許你已經(jīng)注意到在上面MethodSecurityInterceptor的配置例子中的validateConfigAttributes屬性。當(dāng)設(shè)置為true時(shí)(缺省值),在系統(tǒng)啟動(dòng)時(shí)MethodSecurityInterceptor將會(huì)校驗(yàn)設(shè)置的配置屬性是否有效。它檢查每一個(gè)配置屬性能否被 AccessDecisionManager或RunAsManager處理。如果兩者都不能處理給定的配置屬性,將會(huì)被拋出一個(gè)異常。如果你使用 Jakarta Commons Attributes方式進(jìn)行屬性配置,你應(yīng)將validateConfigAttributes屬性設(shè)置為 false。

    注意:當(dāng)使用BeanNameAutoProxyCreator來(lái)創(chuàng)建所需的安全代理時(shí),配置中必須把 proxyTargetClass屬性設(shè)為T(mén)rue.否則,通過(guò)MethodSecurityInterceptor.invoke的檢查方法是代理的調(diào)用者,而不是代理的目標(biāo).請(qǐng)注意這里引入了CGLIB的需求.下面請(qǐng)看BeanNameAutoProxyCreator使用的例子.

    <bean id="autoProxyCreator"
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
    <list><value>methodSecurityInterceptor</value></list>
    </property>
    <property name="beanNames">
    <list><value>targetObjectName</value></list>
    </property>
    <property name="proxyTargetClass" value="true"/>
    </bean>
    1.5.3 AspectJ(連接點(diǎn))安全性攔截器

    AspectJ安全性攔截器與上一節(jié)討論的AOP Alliance安全性攔截器非常相似.在這節(jié)中我們將只討論它們的不同部分.

    AspectJ 攔截器命名為AspectJSecurityInterceptor,不象AOP Alliance安全性攔截器通過(guò)代理依靠Spring應(yīng)用上下文來(lái)設(shè)定那樣,AspectJSecurityInterceptor通過(guò)AspectJ 編譯器來(lái)設(shè)定.在同樣的應(yīng)用中使用這兩種攔截器將很常見(jiàn), AspectJSecurityInterceptor用于域?qū)ο髮?shí)例,而AOP Alliance安全性攔截器用于服務(wù)層的安全.

    首先考慮AspectJSecurityInterceptor在Spring應(yīng)用上下文中是怎么配置的:

    <bean id="bankManagerSecurity"
    class="org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor">
    <property name="validateConfigAttributes"><value>true</value></property>
    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
    <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
    <property name="runAsManager"><ref bean="runAsManager"/></property>
    <property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property>
    <property name="objectDefinitionSource">
    <value>
    org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
    org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
    </value>
    </property>
    </bean>

    如你所見(jiàn),除了類(lèi)名,AspectJSecurityInterceptor與AOP Alliance安全性攔截器完全相同.的確,兩個(gè)攔截器共享同樣的 objectDefinitionSource,因?yàn)閛bjectDefinitionSource是通過(guò) java.lang.reflect.Methods起作用,而不是AOP特定庫(kù)是的類(lèi)來(lái)起作用的.
    當(dāng)然,在做存取決定時(shí),你可以通過(guò)相關(guān)的AOP特定庫(kù)調(diào)用來(lái)存取(例如MethodInvocation 或 JoinPoint),也可以考慮通過(guò)一系列附加的證書(shū)來(lái)實(shí)施存取控制.

    接下來(lái),需要定義一個(gè)AspectJ的aspect,例如:

    package org.acegisecurity.samples.aspectj;
    import org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor;
    import org.acegisecurity.intercept.method.aspectj.AspectJCallback;
    import org.springframework.beans.factory.InitializingBean;
    public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
    private AspectJSecurityInterceptor securityInterceptor;
    pointcut domainObjectInstanceExecution(): target(PersistableEntity)
    && execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
    Object around(): domainObjectInstanceExecution() {
    if (this.securityInterceptor != null) {
    AspectJCallback callback = new AspectJCallback() {
    public Object proceedWithObject() {
    return proceed();
    }
    };
    return this.securityInterceptor.invoke(thisJoinPoint, callback);
    } else {
    return proceed();
    }
    }
    public AspectJSecurityInterceptor getSecurityInterceptor() {
    return securityInterceptor;
    }
    public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
    this.securityInterceptor = securityInterceptor;
    }
    public void afterPropertiesSet() throws Exception {
    if (this.securityInterceptor == null)
    throw new IllegalArgumentException("securityInterceptor required");
    }
    }

    在上面的例子中,安全性攔截器應(yīng)用到PersistableEntity的每一個(gè)實(shí)例中,PersistableEntity是一個(gè)抽象類(lèi)沒(méi)有顯示出來(lái)(你可以用任何其它類(lèi)或pointcut類(lèi)來(lái)表示,只要你喜歡).這看起來(lái)有點(diǎn)古怪,proceed()需要調(diào)用AspectJCallback,在 around()函數(shù)體內(nèi)的語(yǔ)句有著特殊的意義.當(dāng)AspectJSecurityInterceptor想要目標(biāo)對(duì)象繼續(xù)執(zhí)行時(shí),它將調(diào)用這個(gè)匿名的 AspectJCallback.

    你需要配置Spring來(lái)加載aspect,并把它與AspectJSecurityInterceptor關(guān)聯(lián)起來(lái),完成此任務(wù)的bean聲明如下所示:

    <bean id="domainObjectInstanceSecurityAspect"
    class="org.acegisecurity.samples.aspectj.DomainObjectInstanceSecurityAspect"
    factory-method="aspectOf">
    <property name="securityInterceptor"><ref bean="aspectJSecurityInterceptor"/></property>
    </bean>

    好了,現(xiàn)在你可以在你應(yīng)用程序的任何地方用你想要適配的任何意思去創(chuàng)建你的beans,它們都會(huì)用到這個(gè)安全性攔截器.

    1.5.4 FilterInvocation(過(guò)濾器調(diào)用)安全性攔截器

    為了對(duì)FilterInvocation對(duì)象提供保護(hù),開(kāi)發(fā)者需要在web.xml中添加一個(gè)攔截器,來(lái)代理SecurityEnforcementFilter。一個(gè)典型的配置例子如下所示:

    <filter>
    <filter-name>Acegi HTTP Request Security Filter</filter-name>
    <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
    <init-param>
    <param-name>targetClass</param-name>
    <param-value>org.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>Acegi HTTP Request Security Filter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    注意,這里這個(gè)filter實(shí)際上是一個(gè)FilterToBeanProxy??從filter到bean的代理。Acegi安全系統(tǒng)中絕大多數(shù)的filter都使用這個(gè)類(lèi)。將會(huì)在filter一節(jié)中講述它的更多內(nèi)容。

    在應(yīng)用上下文中,你需要配置三個(gè)bean:

    <bean id="securityEnforcementFilter"
    class="org.acegisecurity.intercept.web.SecurityEnforcementFilter">
    <property name="filterSecurityInterceptor"><ref bean="filterInvocationInterceptor"/></property>
    <property name="authenticationEntryPoint"><ref bean="authenticationEntryPoint"/></property>
    </bean>
    <bean id="authenticationEntryPoint"
    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
    <property name="loginFormUrl"><value>/acegilogin.jsp</value></property>
    <property name="forceHttps"><value>false</value></property>
    </bean>
    <bean id="filterInvocationInterceptor"
    class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
    <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
    <property name="runAsManager"><ref bean="runAsManager"/></property>
    <property name="objectDefinitionSource">
    <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    \A/secure/super/.*\Z=ROLE_WE_DONT_HAVE
    \A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_TELLER
    </value>
    </property>
    </bean>

    當(dāng)用戶(hù)請(qǐng)求一個(gè)受保護(hù)的HTTP資源而沒(méi)有通過(guò)認(rèn)證時(shí),authenticationEntryPoint就會(huì)被調(diào)用。這個(gè)類(lèi)負(fù)責(zé)將適當(dāng)?shù)捻憫?yīng)呈現(xiàn)給用戶(hù),因此,開(kāi)始認(rèn)證,Acegi安全系統(tǒng)為認(rèn)證提供了三種具體的認(rèn)證實(shí)現(xiàn): AuthenticationProcessingFilterEntryPoint進(jìn)行表單認(rèn)證; BasicProcessingFilterEntryPoint進(jìn)行HTTP基本認(rèn)證處理; CasProcessingFilterEntryPoint進(jìn)行耶魯集中認(rèn)證服務(wù)(CAS)登錄. AuthenticationProcessingFilterEntryPoint和CasProcessingFilterEntryPoint有與使用HTTPS相關(guān)的可選屬性.如有需要,請(qǐng)參考JavaDoc文檔.

    PortMapper提供了有關(guān)哪個(gè)HTTPS端口對(duì)應(yīng)哪個(gè) HTTP端口的信息.AuthenticationProcessingFilterEntryPoint和其它幾個(gè)bean將使用這些信息. PortMapperImpl是其缺省的實(shí)現(xiàn),它將常用的HTTP 80和8080端口映射對(duì)HTTPS相應(yīng)的443和8443端口;如有需要,你可以定制這個(gè)映射.

    SecurityEnforcementFilter主要在需要是提供會(huì)話管理支持和認(rèn)證初始化.它把真正的FilterInvocation安全判別到配置到FilterSecurityInterceptor中.

    象任何其它安全性攔截器一樣,FilterSecurityInterceptor需要有一份AuthenticationManager, AccessDecisionManager 和 RunAsManager的引用,這些對(duì)象將在下文中分章節(jié)加以討論. FilterSecurityInterceptor也要配置應(yīng)用于不同HTTP URL請(qǐng)求的配置屬性.有關(guān)這些配置屬性的詳細(xì)討論已在本文的系統(tǒng)設(shè)計(jì)章節(jié)是提供.

    FilterSecurityInterceptor的配置屬性可以通過(guò)兩種方式來(lái)配置.第一種是使用屬性編輯和應(yīng)用上下文的方式,就如上面顯示的那樣。第二種方式是書(shū)寫(xiě)你的ObjectDefinitionSource,這超過(guò)了本文的范圍。不管使用那種方式, ObjectDefinitionSource負(fù)責(zé)返回一個(gè)ConfigAttributeDefinition對(duì)象,這個(gè)對(duì)象包括了一個(gè)單個(gè) http url請(qǐng)求所關(guān)聯(lián)的所有配置屬性信息。

    應(yīng)該注意到的是FilterSecurityInterceptor.setObjectDefinitionSource()實(shí)際盼望得到的是一個(gè)FilterInvocationDefinitionSource實(shí)例。這是一個(gè)繼承了ObjectDefinitionSource的標(biāo)記性接口。它簡(jiǎn)單的表示ObjectDefinitionSource理解FilterInvocations。簡(jiǎn)潔的講,我們只需要繼續(xù)使用 FilterInvocationDefinitionSource,就像使用ObjectDefinitionSource一樣,因?yàn)樗麄冎g的區(qū)別就 FilterSecurityInterceptor的角度來(lái)看是非常小的。

    如果使用應(yīng)用上下文屬性編輯的方式(如上所示),應(yīng)用到不同的http rul上的不同配置屬性需要被逗號(hào)分割開(kāi)。每一個(gè)配置屬性都會(huì)分配到它自己的SecurityConfig對(duì)象中。 SecurityConfig對(duì)象在系統(tǒng)設(shè)計(jì)部分已經(jīng)被討論過(guò)。屬性編緝器創(chuàng)建的ObjectDefinitionSource以及 FilterInvocationDefinitionSource要與依賴(lài)于FilterInvocations的配置屬性相匹配. FilterInvocations用于驗(yàn)證所請(qǐng)求的URL表達(dá)是否正確.

    在使用配置屬性對(duì)請(qǐng)求的進(jìn)行匹配和處理時(shí),有兩種標(biāo)準(zhǔn)表達(dá)式語(yǔ)法可以使用。缺省的是使用正則表達(dá)式規(guī)則處理所有的表達(dá)式,另外,顯示的 PATTERN_TYPE_APACHE_ANT標(biāo)明將導(dǎo)致所有的表達(dá)式都使用 Apache Ant paths方式進(jìn)行處理。同一定義內(nèi)同時(shí)使用兩種方式是不允許的。例如上面配置可以被Apache Ant paths 方式書(shū)寫(xiě)成以下形式:

    <bean id="filterInvocationInterceptor"
    class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
    <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
    <property name="runAsManager"><ref bean="runAsManager"/></property>
    <property name="objectDefinitionSource">
    <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /secure/super/**=ROLE_WE_DONT_HAVE
    /secure/**=ROLE_SUPERVISOR,ROLE_TELLER
    </value>
    </property>
    </bean>

    不管使用哪種表達(dá)式語(yǔ)法,表達(dá)式都總是按照它們定義的順序進(jìn)行處理。所以越詳細(xì)的定義越要放在定義的前面,這十分重要。上面的例子中對(duì)這一點(diǎn)體現(xiàn)的很清楚。更具體的/secure/super/模式出現(xiàn)在沒(méi)那么具體的/secure之前,如果反過(guò)來(lái),將總是與/secure模式匹配,而 /secure/supper將永遠(yuǎn)不會(huì)生效.

    特殊的關(guān)鍵字CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON將會(huì)導(dǎo)致 FilterInvocationDefinitionSource在于表達(dá)式進(jìn)行匹配之前會(huì)自動(dòng)轉(zhuǎn)換請(qǐng)求url為小寫(xiě)。缺省情況下請(qǐng)求url是不會(huì)被進(jìn)行轉(zhuǎn)換的,通常情況下建議使用CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON并且書(shū)寫(xiě)表達(dá)式時(shí)都使用小寫(xiě)。
    就像其他的安全攔截器一樣,validateConfigAttributes屬性 是可以進(jìn)行設(shè)置的。當(dāng)設(shè)置為true時(shí)(缺省值),在系統(tǒng)啟動(dòng)時(shí) MethodSecurityInterceptor將會(huì)校驗(yàn)設(shè)置的配置屬性是否有效。它檢查每一個(gè)配置屬性能否被 AccessDecisionManager或RunAsManager處理。如果兩者都不能處理給定的配置屬性,將會(huì)被拋出一個(gè)異常.

    1.6認(rèn)證

    1.6.1 認(rèn)證請(qǐng)求

    認(rèn)證需要用一種客戶(hù)端代碼的方式來(lái)把安全性鑒別信息送到Acegi安全系統(tǒng)中.這就是Authentication接口扮演的角色。 Authentication接口包括三個(gè)重要的對(duì)象:principal(調(diào)用者的身份),credentials(證明調(diào)用者身份的證據(jù),例如密碼),授權(quán)給principal的權(quán)限(列表)。principal 和它的credentials有客戶(hù)端代碼提供,授權(quán)列表由認(rèn)證管理器 (AuthenticationManager)提供。
    500)this.width=500" align=absMiddle border=0>
    如圖3所示,Acegi安全性系統(tǒng)包括幾個(gè)具體的認(rèn)證(Authentication)實(shí)現(xiàn)類(lèi):

    UsernamePasswordAuthenticationToken 允許使用用戶(hù)名(username)和密碼(password)來(lái)表示調(diào)用者(principal)和他的證書(shū)(credentials)。它們也是由 HTTP Session Authentication負(fù)責(zé)創(chuàng)建的。
    TestingAuthenticationToken 主要用作單元測(cè)試,它會(huì)為相應(yīng)的AuthenticationProvider自動(dòng)考慮一個(gè)認(rèn)證對(duì)象。
    RunAsUserToken 被作為默認(rèn)的run-as認(rèn)證置換實(shí)現(xiàn)。這個(gè)將在Run-As Authentication Replacement那節(jié)中進(jìn)一步討論。
    CasAuthenticationToken 用于描述一次成功的耶魯集中認(rèn)證服務(wù) (CAS)。這將在CAS章節(jié)中進(jìn)一步討論。
    PrincipalAcegiUserToken 和JettyAcegiUserToken 實(shí)現(xiàn)了AuthByAdapter (Authentication的子類(lèi))并且它們是在認(rèn)證過(guò)程已經(jīng)被 Acegi系統(tǒng)的容器適配器完成后被使用的。這部分也將在容器適配器章節(jié)中作進(jìn)一步討論。

    對(duì)于主體(principal)的授權(quán)工作是通過(guò)GrantedAuthority進(jìn)行的。GrantedAuthority接口將在下面關(guān)于授權(quán)的章節(jié)中被討論。

    1.6.2 認(rèn)證管理器

    在安全攔截器一節(jié)中我們提到AbstractSecurityInterceptor從SecurityContextHolder中的 SecurityContext里面提取Authentication對(duì)象。緊接著就將它傳遞給AuthenticationManager。 AuthenticationManager接口十分的簡(jiǎn)單:

    public Authentication authenticate(Authentication authentication) throws AuthenticationException;

    AuthenticationManager 的實(shí)現(xiàn)在認(rèn)證失敗的時(shí)候會(huì)拋出一個(gè)異常(AuthenticationException),或者成功時(shí)返回一個(gè)組裝成功的Authentication 對(duì)象。特別要注意,返回的Authentication對(duì)象應(yīng)該包括一組GrantedAuthority對(duì)象。安全攔截器將返回的、組裝后的 Authentication對(duì)象放回到SecurityContextHolder中的SecurityContext里,用以替換原來(lái)的那個(gè) Authentication對(duì)象。

    AuthenticationException有幾個(gè)子類(lèi),其中最重要的是 BadCredentialsException (主體(principal)或者(證據(jù))credentials錯(cuò)誤), DisabledException和LockedException.后面兩個(gè)異常表示主體已經(jīng)發(fā)現(xiàn)(principal)但是證據(jù)沒(méi)有通過(guò)檢驗(yàn)還有認(rèn)證被否決、拒絕。AuthenticationServiceException也會(huì)被使用,它表明認(rèn)證系統(tǒng)不能處理請(qǐng)求(例如數(shù)據(jù)庫(kù)不可用引起)。 AuthenticationException 還有CredentialsExpiredException和 AccoungtExpiredException兩個(gè)子類(lèi),雖然它們不是很常用。

    1.6.3 基于供方的認(rèn)證

    盡管最基本的Authentication和AuthenticationManager接口使用戶(hù)可以開(kāi)發(fā)出自己的認(rèn)證系統(tǒng),但是用戶(hù)完全可以考慮使用 Acegi安全系統(tǒng)提供的基于供方的認(rèn)證包。其關(guān)鍵類(lèi)??ProviderManager通過(guò)一組認(rèn)證提供者 (AuthenticationProviders)的形式在bean定義中被配置:

    <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
    <property name="providers">
    <list>
    <ref bean="daoAuthenticationProvider"/>
    <ref bean="someOtherAuthenticationProvider"/>
    </list>
    </property>
    </bean

    ProviderManager 將調(diào)用一系列已注冊(cè)的AuthenticationProvider實(shí)現(xiàn),直到找到一個(gè)表明它能夠認(rèn)證給定的Authentication類(lèi)為止。當(dāng)找到第一個(gè)符合條件的AuthenticationProvider時(shí),它就把它傳遞給認(rèn)證請(qǐng)求。AuthenticationProvider要么拋出一個(gè) AuthenticationException異常,要么返回一個(gè)組裝成功的Authentication對(duì)象.

    ProviderManager 還有幾個(gè)其它重要的函數(shù),它集成了并發(fā)會(huì)話處理支持,它也能將任何由AuthenticationProvider拋出的異常轉(zhuǎn)化和發(fā)布一個(gè)恰當(dāng)?shù)氖录_@些事件可在org.acegisecurity.event.authentication包中找到。高級(jí)用戶(hù)能夠配置 ProviderManager.exceptionMappings屬性從而將不同的異常映射為不同的事件(通常不需要這么做,缺省的事件傳播是恰當(dāng)?shù)??特別是當(dāng)你沒(méi)在ApplicationContext中配置ApplicationListener時(shí),事件就會(huì)簡(jiǎn)單地忽略掉)

    Acegi安全系統(tǒng)所提供的幾個(gè)AuthenticationProvider實(shí)現(xiàn)類(lèi):

    TestingAuthenticationProvider 能夠?qū)estingAuthenticationToken進(jìn)行驗(yàn)證。這種認(rèn)證的限制是它不管TestingAuthenticationToken中包含什么,它都認(rèn)為是有效的。這就使得它在進(jìn)行單元測(cè)試時(shí)變得非常有用,因?yàn)槟憧梢詣?chuàng)建一個(gè)Authentication對(duì)象---它正好對(duì)你需要進(jìn)行測(cè)試的方法進(jìn)行了授權(quán)。這樣你就可以不需要在產(chǎn)品系統(tǒng)中注冊(cè)AuthenticationProvider而能完成需要的測(cè)試環(huán)境搭建了。

    DaoAuthenticationProvider 可以對(duì)通過(guò)對(duì)數(shù)據(jù)庫(kù)數(shù)據(jù)的存取,驗(yàn)證UsernamePasswordAuthenticationToken。這個(gè)方面將在下面的章節(jié)進(jìn)行討論,因?yàn)樗沁M(jìn)行驗(yàn)證處理的主要工作方式。
    RunAsImplAuthenticationProvider 用以驗(yàn)證RunAsUserToken。這個(gè)將在下面Run-As Authentication Replacement章節(jié)進(jìn)行討論。如果你不使用 run-as處理機(jī)制,你不需要注冊(cè)此AuthenticationProvider。
    AuthByAdapterProvider 能夠驗(yàn)證任何的AuthByAdapter (a subclass of Authentication used with container adapters)。這部分內(nèi)容將在下面的章節(jié)進(jìn)行討論。如果你不使用容器適配器,你不需要注冊(cè)此AuthenticationProvider。
    CasAuthenticationProvider 用來(lái)驗(yàn)證CAS,將在下面章節(jié)進(jìn)行討論。
    JaasAuthenticationProvider 將會(huì)將認(rèn)證請(qǐng)求指派到JAAS登錄模塊,這將在下文進(jìn)行討論。
    1.6.4 并發(fā)會(huì)話支持

    Acegi安全系統(tǒng)具有阻止同一主體并發(fā)訪問(wèn)同一web應(yīng)用資源的能力。例如:你可以阻止用戶(hù)"batman"同一時(shí)間內(nèi)兩次進(jìn)行系統(tǒng)登錄。

    為了使用并發(fā)會(huì)話支持,你需要在web.xml是加入下列語(yǔ)句:

    <listener>
    <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
    </listener>

    另外,你需要將org.acegisecurity.concurrent.ConcurrentSessionFilter加入到你的 FilterChainProxy中。并發(fā)會(huì)話過(guò)濾器需要配置唯一一個(gè)sessionRegistry的屬性,它通常指向 SessionRegistryImpl實(shí)例。

    每次HttpSession開(kāi)始或終止時(shí),web.xml中的 HttpSessionEventPublish都會(huì)產(chǎn)生一個(gè)ApplicationEvent事件并通知Spring的 ApplicationContext.這非常關(guān)鍵,因?yàn)樗试SSessionRegistryImpl注意到會(huì)話會(huì)在何時(shí)結(jié)束。

    你也需要建立ConcurrentSessionControllerImpl,并在ProviderManager中引用它。

    <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
    <property name="providers">
    <!-- your providers go here -->
    </property>
    <property name="sessionController"><ref bean="concurrentSessionController"/></property>
    </bean>

    <bean id="concurrentSessionController" class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl">
    <property name="maximumSessions"><value>1</value></property>
    <property name="sessionRegistry"><ref local="sessionRegistry"/></property>
    </bean>

    <bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl"/>
    1.6.5 數(shù)據(jù)存取對(duì)象認(rèn)證提供者

    Acegi 安全系統(tǒng)包含一個(gè)產(chǎn)品級(jí)的認(rèn)證提供者(AuthenticationProvider)實(shí)現(xiàn)??DaoAuthenticationProvider,這個(gè)認(rèn)證提供者通過(guò)獲得在創(chuàng)建bean時(shí)配置在數(shù)據(jù)存取對(duì)象中的認(rèn)證詳細(xì)信息,從而能夠認(rèn)證 UsernamePasswordAuthenticationToken

    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
    <property name="saltSource"><ref bean="saltSource"/></property>
    <property name="passwordEncoder"><ref bean="passwordEncoder"/></property>
    </bean>

    其中PasswordEncoder和SaltSource是可選的,PasswordEncoder負(fù)責(zé)對(duì)認(rèn)證庫(kù)中的密碼進(jìn)行加解密.而 SaltSource則是在產(chǎn)生密碼時(shí)給它加點(diǎn)"鹽",以增強(qiáng)密碼在認(rèn)證庫(kù)中的安全性.Acegi安全系統(tǒng)提供的PasswordEncoder實(shí)現(xiàn)中包括MD5、SHA和明文編碼。Acegi安全系統(tǒng)也提供兩個(gè)SaltSource的實(shí)現(xiàn):SystemWideSaltSource,它用同樣的"鹽"對(duì)系統(tǒng)中所有的密碼進(jìn)行編碼,而ReflectionSaltSource只對(duì)從UserDetails對(duì)象返回的獲得這種"鹽"的指定屬性進(jìn)行檢查。請(qǐng)參考JavaDoc以獲取對(duì)這些可選特性的更詳細(xì)信息。

    除上屬性外,DaoAuthenticationProvider也支持對(duì) UserDetails對(duì)象的緩存。UserCache接口使DaoAuthenticationProvider能把UserDetails對(duì)象放進(jìn)緩存并可在接下來(lái)對(duì)相同用戶(hù)進(jìn)行認(rèn)證時(shí)在緩存中找回它。在缺省時(shí)DaoAuthenticationProvider使用NullUserCache,表示沒(méi)有使用Cache.Acegi也提供了一個(gè)可用的緩存實(shí)現(xiàn)??EhCacheBasedUserCache,其配置如下:

    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    <property name="userDetailsService"><ref bean="userDetailsService"/></property>
    <property name="userCache"><ref bean="userCache"/></property>
    </bean>

    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation">
    <value>classpath:/ehcache-failsafe.xml</value>
    </property>
    </bean>

    <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
    <property name="cacheManager">
    <ref local="cacheManager"/>
    </property>
    <property name="cacheName">
    <value>userCache</value>
    </property>
    </bean>

    <bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
    <property name="cache"><ref local="userCacheBackend"/></property>
    </bean>

    所有Acegi安全系統(tǒng)的EH-CACHE實(shí)現(xiàn)中(包括EhCacheBasedUserCache),都需要一個(gè)EH-CACHE cache對(duì)象,這個(gè) cache對(duì)象可在你喜歡的任何地方獲得,雖然我們推薦你使用Spring的工廠類(lèi)如上配置中所示。如使用Spring的工廠類(lèi),請(qǐng)參考Spring文檔以獲取如何優(yōu)化的更詳細(xì)的細(xì)節(jié),如緩存存儲(chǔ)本地化、內(nèi)存使用、退出策略、超時(shí)設(shè)定等。

    一個(gè)能為DaoAuthenticationProvider提供存取認(rèn)證庫(kù)的的類(lèi),它必須要實(shí)現(xiàn)UserDetailsService接口:

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;

    UserDetails 是一個(gè)接口,它能提供一系列g(shù)et函數(shù)以獲得認(rèn)證時(shí)需要的基本認(rèn)證信息如用戶(hù)名、密碼、所獲得的授權(quán)、是否禁用等;一個(gè)具體的實(shí)現(xiàn)就是User類(lèi). Acegi用戶(hù)需要決定什么時(shí)候?qū)懰麄兊腢serDetailsService接口以及返回的UserDetails是什么類(lèi)型。在大多數(shù)情況下將使用 User及其子類(lèi),雖然在特定的環(huán)境中(如對(duì)象關(guān)系映射器)也許需要用戶(hù)寫(xiě)他們自己的UserDetails實(shí)現(xiàn)。UserDetails也經(jīng)常用于存儲(chǔ)一些與調(diào)用者相關(guān)的附加信息(如電話號(hào)碼、email地址等)因此它們經(jīng)常在web視圖中使用。

    如果UserDetailsService實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,用戶(hù)應(yīng)當(dāng)很容易從他們選擇的持久化策略中找回認(rèn)證信息。

    DaoAuthenticationProvider設(shè)計(jì)沒(méi)有考慮支持帳戶(hù)鎖定的功能,因?yàn)槟菍⒃黾覷serDetailsService接口的復(fù)雜性。例如需要增加不成功認(rèn)證的計(jì)數(shù),這些功能可能通過(guò)補(bǔ)充應(yīng)用程序的公布特性而很容易提供,這些特性將在下面討論。

    DaoAuthenticationProvider 返回一個(gè)Authentication對(duì)象,它含有principal的屬性集。principal要么是一個(gè)字串(是必需的用戶(hù)名),要么是一個(gè) UserDetails對(duì)象(從UserDetailsService中查找),缺省情況下返回UserDetails。因?yàn)檫@將使應(yīng)用能加上額外的屬性以便在應(yīng)用中使用,如用戶(hù)的全名,Email地址等。如使用容器適配器,或在應(yīng)用中使用Strings(在Acegi 0.6之前的版本就是這樣)你就應(yīng)在你的應(yīng)用上下文中把 DaoAuthenticationProvider.forcePrincipalAsString屬性設(shè)為true。

    1.6.6 In-Memory 認(rèn)證

    雖然使用DaoAuthenticationProvider,從持久化引擎中獲取信息來(lái)創(chuàng)建定制的UserDetailsService實(shí)現(xiàn)很容易,但許多應(yīng)用不需要這么復(fù)雜,一種替代方式是使用InMemoryDaoImpl在應(yīng)用上下文中配置認(rèn)證庫(kù):

    <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
    <property name="userMap">
    <value>
    marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
    dianne=emu,ROLE_TELLER
    scott=wombat,ROLE_TELLER
    peter=opal,disabled,ROLE_TELLER
    </value>
    </property>
    </bean>

    1.6.7 JDBC認(rèn)證
    1.6.8 JAAS認(rèn)證
    1.6.9 Siteminder認(rèn)證
    1.6.10 使用認(rèn)證的幾點(diǎn)建議



    ---------------------------------------------------------------------------------------------------------------------------------
    說(shuō)人之短,乃護(hù)己之短。夸己之長(zhǎng),乃忌人之長(zhǎng)。皆由存心不厚,識(shí)量太狹耳。能去此弊,可以進(jìn)德,可以遠(yuǎn)怨。
    http://m.tkk7.com/szhswl
    ------------------------------------------------------------------------------------------------------ ----------------- ---------
    posted on 2007-12-21 09:20 宋針還 閱讀(474) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): ACEGI
    主站蜘蛛池模板: 一个人看的www免费高清 | 精品国产免费人成电影在线观看| 免费A级毛片无码A| 亚洲精品色播一区二区| www.91亚洲| 国产天堂亚洲精品| 免费在线观看你懂的| 在线观看亚洲视频| 亚洲日本韩国在线| 亚洲一区二区三区在线观看蜜桃 | 精品成人免费自拍视频| 国内免费高清在线观看| 亚洲天堂免费在线| 免费无码毛片一区二区APP| 免费国产美女爽到喷出水来视频| 亚洲国产精品无码观看久久| 国产精品成人无码免费| 特a级免费高清黄色片| 亚洲日产无码中文字幕| 在线免费观看你懂的| 久久久久亚洲精品天堂久久久久久| 日韩一区二区三区免费播放| 黑人大战亚洲人精品一区| 日韩免费在线观看视频| 亚洲最大视频网站| 久久青草免费91线频观看不卡| 色婷婷亚洲十月十月色天| 成人免费视频一区二区| 亚洲精品中文字幕无码蜜桃| 国产亚洲精品成人久久网站| 亚洲一级特黄无码片| 久久国产乱子免费精品| 亚洲男人天堂2022| 亚洲真人日本在线| 免费无码成人AV在线播放不卡| 在线亚洲午夜片AV大片| 黄色免费在线网站| 亚洲熟妇久久精品| 亚洲精品乱码久久久久久久久久久久 | 免费看无码特级毛片| 亚洲国产三级在线观看|