本文檔是"Spring框架下Acegi安全系統(tǒng)"(Acegi Security System for Spring)的一份參考指南,Acegi安全系統(tǒng)是由一序列類構(gòu)成,這些類為Spring框架提供認證和授權(quán)服務(wù)。
我得感謝這份參考在Spring框架中用DocBook配置進行了精心的包裝。Spring小組在他們的DocBook中對Chris Bauer (Hibernate)的幫助表示感謝。
第一章 安全
1.1 準備
為了安全使用Acegi,Acegi的每一個正式發(fā)布的JAR都署上了一個項目前導(dǎo)字符.這不表示對受權(quán)書中的免責(zé)聲明有任何的改變,但它確保你能使用一個適當(dāng)?shù)慕?jīng)過檢查的正式構(gòu)建的Acegi安全系統(tǒng).有關(guān)怎樣驗證JAR文件是否正確地簽署以及哪些證書用來對他們進行認證的說明請參考在發(fā)布版本中根目錄下的readme.txt文件.
1.2介紹
Acegi通過對流行的WEB容器的可選集成而為使用Spring編寫的項目提供認證與授權(quán)的能力.這種安全架構(gòu)是全部用"Spring方式"開發(fā),包括使用bean contexts、攔截器和接口驅(qū)動的編程方式。結(jié)果,對那些為基于Spring應(yīng)用的尋求安全保證應(yīng)用來說,Acegi是一個非常有用的外置式的安全架構(gòu),它很容易適用于各種復(fù)機的用戶化需求。
安全系統(tǒng)保括兩個顯而易見的方面:認證和授權(quán)。前者解決調(diào)用者是否是他們所聲稱的人的問題,而授權(quán)則是關(guān)于已經(jīng)經(jīng)過認證的調(diào)用者是否允許進行給定操作的問題。
在Acegi中,需要認證的用戶、系統(tǒng)或都代理都作為一個"參與者"來題及。這個安全架構(gòu)沒有你在其它安全系統(tǒng)是所熟悉的角色或組的概念,即使Acegi完全提供相應(yīng)的功能。
1.2.1 發(fā)布號
理解Acegi的發(fā)布號的含意是有用的,因為它將有助于證實你已經(jīng)(或者還沒將它)升級到這個項目的未來版本的。正式地,我們使用"Apache Portable Runtime Project"版本號使作指南,你可以在http://apr.apache.org/versioning.html
中看到。為方便起見,我們引用了那頁中的介紹。
"版本號使用標準的三個一組的整數(shù)來表示:主版本號.次版本號.補丁號。主版本號表示API不兼容和對它進行了大型升級。次版本號表示與之前的舊的較小的版本在源代碼和二進制代碼上保持兼容性。補丁級版本號的改變表示無論向前向后完全兼容。
1.3 系統(tǒng)設(shè)計
1.3.1 關(guān)鍵組件
大多數(shù)企業(yè)級的應(yīng)用有四個基本安全需求。首先,他們要能夠認證一個訪問者;其次,他們需要有能力對web請求提供安全保證;第三,企業(yè)級應(yīng)用需要有能力對服務(wù)層方法提供安全保證;最后,企業(yè)級應(yīng)用經(jīng)常要有能力對域?qū)ο髮嵗峁┌踩Wo。Acegi提供了一個通用的框架,來滿足所有這四個通用的企業(yè)級應(yīng)用安全需求。
Acegi基本上由八個關(guān)鍵功能部分組成。
Authentication對象 |
它包括參與者、認證證書和賦予參與者的權(quán)限。這個對象也能存儲一些與認證請求有關(guān)的附加信息。例如源TCP/IP地址. |
SecurityContextHolder對象 |
它包含一個在線程級對象內(nèi)的Authentication 認證對象 |
AuthenticationManager對象 |
它鑒別由ContextHolder引進的Authentication對象. |
AccessDecisionManager對象 |
授權(quán)一個給定的操作。 |
RunAsManager對象 |
當(dāng)一個給定的操作被執(zhí)行時,任意替代Authentication 對象 |
"安全對象"攔截器 |
配合認證、授權(quán)、run-as替換,從而調(diào)用處理執(zhí)行給定的操作。 |
AfterInvocationManager對象 |
能夠修改一個從"安全對象"調(diào)用中返的對象。例如刪去一些參與者沒有授權(quán)存取的集合元素。 |
存取控制列表(ACL)管理包 |
用于獲取應(yīng)用于域?qū)ο髮嵗鼳CLs。 |
"安全對象"攔截器執(zhí)行Acegi安全系統(tǒng)中的大多數(shù)關(guān)鍵類。這樣做是為了利用框架的主要特性。
由于它的重要性,圖1表示了AbstractSecurityInterceptor 攔截器類的主要關(guān)系和具體實現(xiàn)。
500)this.width=500" align=absMiddle border=0>
每個"安全對象"攔截器(下文中稱為"保護性攔截器")作用于一個特殊類型的"安全對象"。那么,什么是安全對象?安全對象是指對它采取了安全保護措施的任何類型的對象。一個安全對象必須提供某種形式回調(diào),這樣當(dāng)需要的時候保護性攔截器就能明顯地起作用。保護性攔截器回調(diào)對象同時繼續(xù)所請求的操作。如果安全對象不能提供一個本地的回調(diào)方法,就要寫一個包裝器來實現(xiàn)它。
每個安全對象都有一個實現(xiàn)它的包放在org.acegisecurity.intercept包中。在安全系統(tǒng)中的每個其它包是一個獨立的安全對象.因此它能支持上述的任何一種安全對象.
只有那些想對攔截和認證請求采用全新方法的開發(fā)者才需要直接使用安全對象.例如有可能建立一個新的安全對象來對沒有使用 MethodInvocations 對象的消息系統(tǒng)提供安全保護.大多數(shù)的Spring應(yīng)用將簡單地完全透明地使用三種普遍支持安全對象類型 ((AOP Alliance MethodInvocation, AspectJ 連接點 和 web 請求過濾攔截器)
Acegi安全系統(tǒng)中八個關(guān)鍵部分的每個部分都將在本文中詳細討論.
1.3.2 所支持的安全對象
如圖1所示,目前Acegi安全系統(tǒng)支持三種安全對象.
第一種對象處理AOP Alliance MethodInvocation.這種安全對象用于保護Spring Bean.開發(fā)者通常用它來保護他們的業(yè)務(wù)對象.為了生成一個標準的Spring-hosted類型的bean 用作MethodInvocation,Bean簡單地通過 ProxyFactoryBean 或者 BeanNameAutoProxyCreator 或者 DefaultAdvisorAutoProxyCreator來公布.大多數(shù)Spring開發(fā)者對此都已很熟悉,因為他們使用過Spring的事務(wù)處理和Spring的其它方面.
第二種對象是AspectJ連接點對象.AspectJ在域?qū)ο髮嵗踩矫嬗幸环N特殊的應(yīng)用,這通常是在 Spring bean容器之外.通過使用AspectJ,利用標準的構(gòu)造函數(shù),如new Person(),Acegi 安全系統(tǒng)對他們提供安全保護. AspectJSecurityInterceptor仍然由Spring管理.它創(chuàng)建Aspect單例,并通過適當(dāng)?shù)恼J證管理器、存取判別管理器等將它聯(lián)系起來。
第三種是過濾器調(diào)用(FilterInvocation)對象.它包含在Acegi安全系統(tǒng)內(nèi)。它由一個包含的過濾器創(chuàng)建并簡單地封裝了HTTP ServletRequest、ServletResponse和FilterChain 。過濾器調(diào)用對象對HTTP資源提供了安全保護。開發(fā)者通常不需要了解它的工作機制,因為他們只要在他們的web.xml中添加過濾器來讓安全系統(tǒng)工作。
1.3.3配置屬性
每一個安全對象都能作用于一些特殊的請求。例如,MethodInvocation能用于對帶有任意參數(shù)的任何方的的調(diào)用。而FilterInvocation能用在任何的HTTP URL上。
Acegi 安全系統(tǒng)需要記錄一些配置信息,這些配置信息用于各種可能的請求。例如BankManager.getBalance (int accountNumber)請求所需的安全配置與BankManager.approveLoan (int applicationNumber)請求所需的安全配置有很大的不同。與此類似,http://some.bank.com/index.htm
請求所需的安全配置與http://some.bank.com/manage/timesheet.jsp
請求所需的安全配置也有很大的不同。
為了存儲針對各種不同請求的各種安全配置,就要使用配置屬性。在實現(xiàn)上配置屬性通過ConfigAttribute接口來表示。SecurityConfig是ConfigAttribute接口的一個具體實現(xiàn),它簡單地把配置屬性當(dāng)作一個串(String)來存儲。
與特定請求相聯(lián)系的ConfigAttributes 集合保存在ConfigAttributeDefinition中。這個類只是一個簡單的ConfigAttributes存儲器,并不做其它特別的處理。
當(dāng)安全性攔截器收到一個請求時,它需要判斷使用哪些配置屬性。換句話說,它需要找到用于這種請求的 ConfigAttributeDefinition.這種判別是通過ObjectDefinitionSource接口來處理的.這個接口提供的主要方法是 public ConfigAttributeDefinition getAttributes(Object object),其中的Object 就是要保護的安全對象。因為安全對象包含了請求的細節(jié),所以O(shè)bjectDefinitionSource實現(xiàn)類將能夠抽取它所需要的細節(jié)來檢查相關(guān)的 ConfigAttributeDefinition.
1.4 Request Contexts
1.4.1以前的方式
Acegi 安全系統(tǒng)在發(fā)布0.9.0以前,使用ContextHolder來存儲session間的上下文信息(Context).Context的一個特殊子類, SecureContext定義了一個接口來存儲認證對象(Authentication object).ContextHolder是一個線程 (ThreadLocal)類型的對象,有關(guān)Acegi安全系統(tǒng)中線程類對象用法的更全面的討論將放在本文的后續(xù)章節(jié)中.為了保持一致,經(jīng)過與其它 Spring開發(fā)者討論,從0.9.0開始,我們將移去ContextHolder和SecureContext.有關(guān)詳情請參考http://article.gmane.org/gmane.comp.java.springframework.devel/8290
和JIRA task SEC-77.這段歷史之所以被提及是因為ContextHolder使用了很長一段時間,你所遇到某些有關(guān)Acegi安全系統(tǒng)的文檔可能仍舊說到了 ContextHolder.通常你可以用SecurityContextHolder替代ContextHolder,用 SecurityContext替代SecureContext,這樣你就能了解這些文檔的主要意思.
1.4.2 SecurityContext
Acegi 安全系統(tǒng)用SecurityContextHolder來存儲SecurityContext.SecurityContext包含有 Authentication的getter/setter方法.為了獲得當(dāng)前SecurityContext(或者參與者),所有Acegi安全類都要查詢SecurityContextHolder.SecurityContextHolder是一個線程,這意味著它與當(dāng)前線程的執(zhí)行有關(guān).
1.4.3 Context Storage
Acegi安全系統(tǒng)設(shè)計的重點就是在兩個web請求之間存儲SecurityContextHolder(它是SecurityContext的實現(xiàn)類)的內(nèi)容.通過SecurityContextHolder獲取存儲在SecurityContext內(nèi)Authentication,這樣成功認證的參與者就能在隨后的請求中鑒別到.HttpSessionContextIntegrationFilter一直存在到自動拷貝一個定義好 HttpSession屬性的內(nèi)容到SecurityContextHolder中,然后,在每一個請求的結(jié)尾,再將 SecurityContextHolder的內(nèi)容拷貝回為下一個請求準備的HttpSession中.
將HttpSessionContextIntegrationFilter放在其它任何 Acegi安全過濾器之前(沒有這樣做是終端用戶很容易犯的一個共同的錯誤)是必須的.當(dāng)覺得合適時,Acegi安全過濾器期望能夠修改 SecurityContextHolder的內(nèi)容,并且如果有必要其它的類(也就是 HttpSessionContextIntegrationFilter)將在請求之間存儲這些信息.這就是為什么 HttpSessionContextIntegrationFilter必須是第一個被用的過濾器.
通過設(shè)置HttpSessionContextIntegrationFilter bean中的context屬性,你能定義一個特定的SecurityContext實現(xiàn)類用到你的應(yīng)用中.
1.4.4 本地化
從1.0.0 開始,Acegi安全系統(tǒng)支持異常消息的本地化,這是終端用戶很希望看到的特性.例如認證失敗和存取被否定(授權(quán)失敗)異常的本地化.那些面向開發(fā)者或系統(tǒng)配置員的異常和日志(包括不正確的屬性、接口約定違背、使用不正確的構(gòu)造函數(shù)、啟動時間確認、調(diào)試級的日志)等沒有本地化,而是用英語硬編碼在 Acegi安全系統(tǒng)的代碼內(nèi).
在org.acegisecurity包內(nèi)裝載的acegi-security-xx.jar是一個 messages.properties文件。當(dāng)Acegi安全類實現(xiàn)Spring的MessageSourceAware接口,并且希望消息解析器在應(yīng)用上下文啟動時被依賴注入時,它就會用到。通常你所需要做的只是在你的應(yīng)用上下文中注冊一個bean來指向這些消息。下面是一個示例。
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename"><value>org/acegisecurity/messages</value></property>
</bean>
messages.properties 文件的命名符合標準資源約束,用Acegi安全消息支持的默認的語言來表示并在上述的bean定義中注冊它。在這個文件內(nèi)沒有許多的消息關(guān)鍵詞,因此本地化不應(yīng)認為是一個主要的問題。如果你打算對這個文件進行本地化,請考慮登記一個JIRA任務(wù)與社區(qū)共享你的工作,并為 messages.properties文件的本地化版本附上一個適當(dāng)?shù)拿帧?/p>
有關(guān)本地化的討論是一個叫 org.springframework.context.i18n.LocaleContextHolder的Spring 線程,Acegi通過使用 Locale來獲得這個線程,從而對一個消息源中的消息實行本地化。Spring文檔為你提供了有關(guān)使用LocaleContextHoldert和能自動設(shè)置它的幫助類(如AcceptHeaderLocaleResolver, CookieLocaleResolver, FixedLocaleResolver, SessionLocaleResolver 等)的更詳細的情況.
1.5 安全性攔截
1.5.1所有的安全對象
如在系統(tǒng)設(shè)計部分描述的那樣,每一個安全對象都有它自己的安全性攔截器來負責(zé)處理每一個請求
 |
處理過程包括以下這些操作:
- 存儲每一個安全請求的配置屬性。
- 從相應(yīng)的ObjectDefinitionSource提取 ConfigAttributeDefinition應(yīng)用到請求中。
- 從SecurityContext中獲取Authentication對象,這個對象保存在SecurityContextHolder中。
- 傳遞Authentication對象到AuthenticationManager中,通過響應(yīng)更新SecurityContextHolder。
- 傳遞Authentication 對象、ConfigAttributeDefinition和安全對象到AccessDecisionManager中。
- 傳遞Authentication 對象、ConfigAttributeDefinition和安全對象到RunAsManager中。
- 如果RunAsManager對象返回一個新的Authentication 對象,就用它更新SecurityContextHolder對象。
- 繼續(xù)執(zhí)行安全對象的請求。
- 如果上一步中RunAsManager對象返回一個新的Authentication對象,就用它更新以前從AuthenticationManager中返回的SecurityContextHolder對象。
- 如果定義了AfterInvocationManager,把安全對象的執(zhí)行結(jié)果傳遞給它。從而它可以拋出AccessDeniedException異常,接受可能需要的返回對象。
- 返回從AfterInvocationManager處收到的任何結(jié)果,或如沒定義AfterInvocationManager,就返回一個安全對象執(zhí)行后提供的簡單結(jié)果。
|
雖然看起來有點麻煩,但別擔(dān)心;開發(fā)者與安全處理的交互只是簡單地使用幾個基本的接口(如AccessDecisionManager)實現(xiàn)來完成的。下面我們將詳細的討論它們。
AbstractSecurityInterceptor處理了上述過程的大部分。如圖一所示,每個安全對象都有它自已的安全性攔截器,它們是AbstractSecurityInterceptor的子類。這些安全對象--具體的安全性攔截器都將在下面詳細討論。
1.5.2 AOP Alliance(MethodInvocation)安全性攔截器
為了對MethodInvocations對象提供保護,開發(fā)者只需要簡單地加上恰當(dāng)配置的方法安全性攔截器(MethodSecurityInterceptor)到你的應(yīng)用中,然后將需要查詢的bean鏈接到攔截器鏈中去。這種鏈接方法由Spring的 ProxyFactoryBean或BeanNameAutoProxyCreator來完成,就如Spring的許多其它部分的用法(請參考應(yīng)用實例)一樣,另外,Acegi安全系統(tǒng)也提供一個MethodDefinitionSourceAdvisor,它將使用Spring的 DefaultAdvisorAutoProxyCreator自動鏈接MethodSecurityInterceptor之前的任何bean到這個安全性攔截器;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配置了三個引用:AuthenticationManager, AccessDecisionManager和RunAsManager。下面我們將分節(jié)討論它們。在這個例子中我們將定義 AfterInvocationManager,雖然它是可選的。MethodSecurityInterceptor也是通過"配置屬性"來配置的,這些配置屬性用于不同的方法簽名。有關(guān)配置屬性的全面的論述已在本文的系統(tǒng)設(shè)計部分提供。
MethodSecurityInterceptor 有三種通過配置屬性來配置的方法,第一種是經(jīng)由屬性編輯器和應(yīng)用上下文,如上所示。第二種使用Jakarta Commons Attributes或 Java 5 Annotation在你的源代碼中通過定義配置屬性來配置。第三種方法是你自己寫一個ObjectDefinitionSource,雖然這已超出本文檔的范圍。
不管使用哪種方法,ObjectDefinitionSource都會相應(yīng)地返回一個ConfigAttributeDefinition對象,ConfigAttributeDefinition對象含有一個單獨的安全方法的所有配置屬性。
應(yīng)用注意:MethodSecurityInterceptor.setObjectDefinitionSource()方法實際需要一個 MethodDefinitionSource實例,這是一個標志性接口,是ObjectDefinitionSource的一個子類。它簡單地指示 ObjectDefinitionSource認到MethodInvocations。為了簡單起見,我們將繼續(xù)把 MethodDefinitionSource當(dāng)作ObjectDefinitionSource,因為對大多數(shù)使用 MethodSecurityInterceptor用戶來說,區(qū)別很小。
如果使用應(yīng)用上下文屬性編輯器方法(如上所示),要使用逗號來區(qū)隔不同應(yīng)用于給定方法模式的配置屬性.每一個配置屬性都將賦值到它們本身的SecurityConfig對象中去.SecurityConfig對象已在系統(tǒng)設(shè)計部分討論.
如果你使用Jakarta Commons Attributes方式,你的bean上下文配置將會是不同的,如下所示:
<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標記.用它來指示ConfigAttribute的一個具體實現(xiàn).
下面這個例子使用SecurityConfig實現(xiàn)來表示配置屬性,其結(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,用它來表示ConfigAttribute,下面的例子使用@Secured注釋來表示配置屬性.其結(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時(缺省值),在系統(tǒng)啟動時MethodSecurityInterceptor將會校驗設(shè)置的配置屬性是否有效。它檢查每一個配置屬性能否被 AccessDecisionManager或RunAsManager處理。如果兩者都不能處理給定的配置屬性,將會被拋出一個異常。如果你使用 Jakarta Commons Attributes方式進行屬性配置,你應(yīng)將validateConfigAttributes屬性設(shè)置為 false。
注意:當(dāng)使用BeanNameAutoProxyCreator來創(chuàng)建所需的安全代理時,配置中必須把 proxyTargetClass屬性設(shè)為True.否則,通過MethodSecurityInterceptor.invoke的檢查方法是代理的調(diào)用者,而不是代理的目標.請注意這里引入了CGLIB的需求.下面請看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(連接點)安全性攔截器
AspectJ安全性攔截器與上一節(jié)討論的AOP Alliance安全性攔截器非常相似.在這節(jié)中我們將只討論它們的不同部分.
AspectJ 攔截器命名為AspectJSecurityInterceptor,不象AOP Alliance安全性攔截器通過代理依靠Spring應(yīng)用上下文來設(shè)定那樣,AspectJSecurityInterceptor通過AspectJ 編譯器來設(shè)定.在同樣的應(yīng)用中使用這兩種攔截器將很常見, AspectJSecurityInterceptor用于域?qū)ο髮嵗?而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>
如你所見,除了類名,AspectJSecurityInterceptor與AOP Alliance安全性攔截器完全相同.的確,兩個攔截器共享同樣的 objectDefinitionSource,因為objectDefinitionSource是通過 java.lang.reflect.Methods起作用,而不是AOP特定庫是的類來起作用的.
當(dāng)然,在做存取決定時,你可以通過相關(guān)的AOP特定庫調(diào)用來存取(例如MethodInvocation 或 JoinPoint),也可以考慮通過一系列附加的證書來實施存取控制.
接下來,需要定義一個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的每一個實例中,PersistableEntity是一個抽象類沒有顯示出來(你可以用任何其它類或pointcut類來表示,只要你喜歡).這看起來有點古怪,proceed()需要調(diào)用AspectJCallback,在 around()函數(shù)體內(nèi)的語句有著特殊的意義.當(dāng)AspectJSecurityInterceptor想要目標對象繼續(xù)執(zhí)行時,它將調(diào)用這個匿名的 AspectJCallback.
你需要配置Spring來加載aspect,并把它與AspectJSecurityInterceptor關(guān)聯(lián)起來,完成此任務(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,它們都會用到這個安全性攔截器.
1.5.4 FilterInvocation(過濾器調(diào)用)安全性攔截器
為了對FilterInvocation對象提供保護,開發(fā)者需要在web.xml中添加一個攔截器,來代理SecurityEnforcementFilter。一個典型的配置例子如下所示:
<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>
注意,這里這個filter實際上是一個FilterToBeanProxy??從filter到bean的代理。Acegi安全系統(tǒng)中絕大多數(shù)的filter都使用這個類。將會在filter一節(jié)中講述它的更多內(nèi)容。
在應(yīng)用上下文中,你需要配置三個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)用戶請求一個受保護的HTTP資源而沒有通過認證時,authenticationEntryPoint就會被調(diào)用。這個類負責(zé)將適當(dāng)?shù)捻憫?yīng)呈現(xiàn)給用戶,因此,開始認證,Acegi安全系統(tǒng)為認證提供了三種具體的認證實現(xiàn): AuthenticationProcessingFilterEntryPoint進行表單認證; BasicProcessingFilterEntryPoint進行HTTP基本認證處理; CasProcessingFilterEntryPoint進行耶魯集中認證服務(wù)(CAS)登錄. AuthenticationProcessingFilterEntryPoint和CasProcessingFilterEntryPoint有與使用HTTPS相關(guān)的可選屬性.如有需要,請參考JavaDoc文檔.
PortMapper提供了有關(guān)哪個HTTPS端口對應(yīng)哪個 HTTP端口的信息.AuthenticationProcessingFilterEntryPoint和其它幾個bean將使用這些信息. PortMapperImpl是其缺省的實現(xiàn),它將常用的HTTP 80和8080端口映射對HTTPS相應(yīng)的443和8443端口;如有需要,你可以定制這個映射.
SecurityEnforcementFilter主要在需要是提供會話管理支持和認證初始化.它把真正的FilterInvocation安全判別到配置到FilterSecurityInterceptor中.
象任何其它安全性攔截器一樣,FilterSecurityInterceptor需要有一份AuthenticationManager, AccessDecisionManager 和 RunAsManager的引用,這些對象將在下文中分章節(jié)加以討論. FilterSecurityInterceptor也要配置應(yīng)用于不同HTTP URL請求的配置屬性.有關(guān)這些配置屬性的詳細討論已在本文的系統(tǒng)設(shè)計章節(jié)是提供.
FilterSecurityInterceptor的配置屬性可以通過兩種方式來配置.第一種是使用屬性編輯和應(yīng)用上下文的方式,就如上面顯示的那樣。第二種方式是書寫你的ObjectDefinitionSource,這超過了本文的范圍。不管使用那種方式, ObjectDefinitionSource負責(zé)返回一個ConfigAttributeDefinition對象,這個對象包括了一個單個 http url請求所關(guān)聯(lián)的所有配置屬性信息。
應(yīng)該注意到的是FilterSecurityInterceptor.setObjectDefinitionSource()實際盼望得到的是一個FilterInvocationDefinitionSource實例。這是一個繼承了ObjectDefinitionSource的標記性接口。它簡單的表示ObjectDefinitionSource理解FilterInvocations。簡潔的講,我們只需要繼續(xù)使用 FilterInvocationDefinitionSource,就像使用ObjectDefinitionSource一樣,因為他們之間的區(qū)別就 FilterSecurityInterceptor的角度來看是非常小的。
如果使用應(yīng)用上下文屬性編輯的方式(如上所示),應(yīng)用到不同的http rul上的不同配置屬性需要被逗號分割開。每一個配置屬性都會分配到它自己的SecurityConfig對象中。 SecurityConfig對象在系統(tǒng)設(shè)計部分已經(jīng)被討論過。屬性編緝器創(chuàng)建的ObjectDefinitionSource以及 FilterInvocationDefinitionSource要與依賴于FilterInvocations的配置屬性相匹配. FilterInvocations用于驗證所請求的URL表達是否正確.
在使用配置屬性對請求的進行匹配和處理時,有兩種標準表達式語法可以使用。缺省的是使用正則表達式規(guī)則處理所有的表達式,另外,顯示的 PATTERN_TYPE_APACHE_ANT標明將導(dǎo)致所有的表達式都使用 Apache Ant paths方式進行處理。同一定義內(nèi)同時使用兩種方式是不允許的。例如上面配置可以被Apache Ant paths 方式書寫成以下形式:
<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>
不管使用哪種表達式語法,表達式都總是按照它們定義的順序進行處理。所以越詳細的定義越要放在定義的前面,這十分重要。上面的例子中對這一點體現(xiàn)的很清楚。更具體的/secure/super/模式出現(xiàn)在沒那么具體的/secure之前,如果反過來,將總是與/secure模式匹配,而 /secure/supper將永遠不會生效.
特殊的關(guān)鍵字CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON將會導(dǎo)致 FilterInvocationDefinitionSource在于表達式進行匹配之前會自動轉(zhuǎn)換請求url為小寫。缺省情況下請求url是不會被進行轉(zhuǎn)換的,通常情況下建議使用CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON并且書寫表達式時都使用小寫。
就像其他的安全攔截器一樣,validateConfigAttributes屬性 是可以進行設(shè)置的。當(dāng)設(shè)置為true時(缺省值),在系統(tǒng)啟動時 MethodSecurityInterceptor將會校驗設(shè)置的配置屬性是否有效。它檢查每一個配置屬性能否被 AccessDecisionManager或RunAsManager處理。如果兩者都不能處理給定的配置屬性,將會被拋出一個異常.
1.6認證
1.6.1 認證請求
認證需要用一種客戶端代碼的方式來把安全性鑒別信息送到Acegi安全系統(tǒng)中.這就是Authentication接口扮演的角色。 Authentication接口包括三個重要的對象:principal(調(diào)用者的身份),credentials(證明調(diào)用者身份的證據(jù),例如密碼),授權(quán)給principal的權(quán)限(列表)。principal 和它的credentials有客戶端代碼提供,授權(quán)列表由認證管理器 (AuthenticationManager)提供。
500)this.width=500" align=absMiddle border=0>
如圖3所示,Acegi安全性系統(tǒng)包括幾個具體的認證(Authentication)實現(xiàn)類:
UsernamePasswordAuthenticationToken |
允許使用用戶名(username)和密碼(password)來表示調(diào)用者(principal)和他的證書(credentials)。它們也是由 HTTP Session Authentication負責(zé)創(chuàng)建的。 |
TestingAuthenticationToken |
主要用作單元測試,它會為相應(yīng)的AuthenticationProvider自動考慮一個認證對象。 |
RunAsUserToken |
被作為默認的run-as認證置換實現(xiàn)。這個將在Run-As Authentication Replacement那節(jié)中進一步討論。 |
CasAuthenticationToken |
用于描述一次成功的耶魯集中認證服務(wù) (CAS)。這將在CAS章節(jié)中進一步討論。 |
PrincipalAcegiUserToken 和JettyAcegiUserToken |
實現(xiàn)了AuthByAdapter (Authentication的子類)并且它們是在認證過程已經(jīng)被 Acegi系統(tǒng)的容器適配器完成后被使用的。這部分也將在容器適配器章節(jié)中作進一步討論。 |
對于主體(principal)的授權(quán)工作是通過GrantedAuthority進行的。GrantedAuthority接口將在下面關(guān)于授權(quán)的章節(jié)中被討論。
1.6.2 認證管理器
在安全攔截器一節(jié)中我們提到AbstractSecurityInterceptor從SecurityContextHolder中的 SecurityContext里面提取Authentication對象。緊接著就將它傳遞給AuthenticationManager。 AuthenticationManager接口十分的簡單:
public Authentication authenticate(Authentication authentication) throws AuthenticationException;
AuthenticationManager 的實現(xiàn)在認證失敗的時候會拋出一個異常(AuthenticationException),或者成功時返回一個組裝成功的Authentication 對象。特別要注意,返回的Authentication對象應(yīng)該包括一組GrantedAuthority對象。安全攔截器將返回的、組裝后的 Authentication對象放回到SecurityContextHolder中的SecurityContext里,用以替換原來的那個 Authentication對象。
AuthenticationException有幾個子類,其中最重要的是 BadCredentialsException (主體(principal)或者(證據(jù))credentials錯誤), DisabledException和LockedException.后面兩個異常表示主體已經(jīng)發(fā)現(xiàn)(principal)但是證據(jù)沒有通過檢驗還有認證被否決、拒絕。AuthenticationServiceException也會被使用,它表明認證系統(tǒng)不能處理請求(例如數(shù)據(jù)庫不可用引起)。 AuthenticationException 還有CredentialsExpiredException和 AccoungtExpiredException兩個子類,雖然它們不是很常用。
1.6.3 基于供方的認證
盡管最基本的Authentication和AuthenticationManager接口使用戶可以開發(fā)出自己的認證系統(tǒng),但是用戶完全可以考慮使用 Acegi安全系統(tǒng)提供的基于供方的認證包。其關(guān)鍵類??ProviderManager通過一組認證提供者 (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)用一系列已注冊的AuthenticationProvider實現(xiàn),直到找到一個表明它能夠認證給定的Authentication類為止。當(dāng)找到第一個符合條件的AuthenticationProvider時,它就把它傳遞給認證請求。AuthenticationProvider要么拋出一個 AuthenticationException異常,要么返回一個組裝成功的Authentication對象.
ProviderManager 還有幾個其它重要的函數(shù),它集成了并發(fā)會話處理支持,它也能將任何由AuthenticationProvider拋出的異常轉(zhuǎn)化和發(fā)布一個恰當(dāng)?shù)氖录_@些事件可在org.acegisecurity.event.authentication包中找到。高級用戶能夠配置 ProviderManager.exceptionMappings屬性從而將不同的異常映射為不同的事件(通常不需要這么做,缺省的事件傳播是恰當(dāng)?shù)??特別是當(dāng)你沒在ApplicationContext中配置ApplicationListener時,事件就會簡單地忽略掉)
Acegi安全系統(tǒng)所提供的幾個AuthenticationProvider實現(xiàn)類:
TestingAuthenticationProvider 能夠?qū)estingAuthenticationToken進行驗證。這種認證的限制是它不管TestingAuthenticationToken中包含什么,它都認為是有效的。這就使得它在進行單元測試時變得非常有用,因為你可以創(chuàng)建一個Authentication對象---它正好對你需要進行測試的方法進行了授權(quán)。這樣你就可以不需要在產(chǎn)品系統(tǒng)中注冊AuthenticationProvider而能完成需要的測試環(huán)境搭建了。
DaoAuthenticationProvider |
可以對通過對數(shù)據(jù)庫數(shù)據(jù)的存取,驗證UsernamePasswordAuthenticationToken。這個方面將在下面的章節(jié)進行討論,因為它是進行驗證處理的主要工作方式。 |
RunAsImplAuthenticationProvider |
用以驗證RunAsUserToken。這個將在下面Run-As Authentication Replacement章節(jié)進行討論。如果你不使用 run-as處理機制,你不需要注冊此AuthenticationProvider。 |
AuthByAdapterProvider |
能夠驗證任何的AuthByAdapter (a subclass of Authentication used with container adapters)。這部分內(nèi)容將在下面的章節(jié)進行討論。如果你不使用容器適配器,你不需要注冊此AuthenticationProvider。 |
CasAuthenticationProvider |
用來驗證CAS,將在下面章節(jié)進行討論。 |
JaasAuthenticationProvider |
將會將認證請求指派到JAAS登錄模塊,這將在下文進行討論。 |
1.6.4 并發(fā)會話支持
Acegi安全系統(tǒng)具有阻止同一主體并發(fā)訪問同一web應(yīng)用資源的能力。例如:你可以阻止用戶"batman"同一時間內(nèi)兩次進行系統(tǒng)登錄。
為了使用并發(fā)會話支持,你需要在web.xml是加入下列語句:
<listener>
<listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
另外,你需要將org.acegisecurity.concurrent.ConcurrentSessionFilter加入到你的 FilterChainProxy中。并發(fā)會話過濾器需要配置唯一一個sessionRegistry的屬性,它通常指向 SessionRegistryImpl實例。
每次HttpSession開始或終止時,web.xml中的 HttpSessionEventPublish都會產(chǎn)生一個ApplicationEvent事件并通知Spring的 ApplicationContext.這非常關(guān)鍵,因為它允許SessionRegistryImpl注意到會話會在何時結(jié)束。
你也需要建立ConcurrentSessionControllerImpl,并在ProviderManager中引用它。
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
</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ù)存取對象認證提供者
Acegi 安全系統(tǒng)包含一個產(chǎn)品級的認證提供者(AuthenticationProvider)實現(xiàn)??DaoAuthenticationProvider,這個認證提供者通過獲得在創(chuàng)建bean時配置在數(shù)據(jù)存取對象中的認證詳細信息,從而能夠認證 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負責(zé)對認證庫中的密碼進行加解密.而 SaltSource則是在產(chǎn)生密碼時給它加點"鹽",以增強密碼在認證庫中的安全性.Acegi安全系統(tǒng)提供的PasswordEncoder實現(xiàn)中包括MD5、SHA和明文編碼。Acegi安全系統(tǒng)也提供兩個SaltSource的實現(xiàn):SystemWideSaltSource,它用同樣的"鹽"對系統(tǒng)中所有的密碼進行編碼,而ReflectionSaltSource只對從UserDetails對象返回的獲得這種"鹽"的指定屬性進行檢查。請參考JavaDoc以獲取對這些可選特性的更詳細信息。
除上屬性外,DaoAuthenticationProvider也支持對 UserDetails對象的緩存。UserCache接口使DaoAuthenticationProvider能把UserDetails對象放進緩存并可在接下來對相同用戶進行認證時在緩存中找回它。在缺省時DaoAuthenticationProvider使用NullUserCache,表示沒有使用Cache.Acegi也提供了一個可用的緩存實現(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實現(xiàn)中(包括EhCacheBasedUserCache),都需要一個EH-CACHE cache對象,這個 cache對象可在你喜歡的任何地方獲得,雖然我們推薦你使用Spring的工廠類如上配置中所示。如使用Spring的工廠類,請參考Spring文檔以獲取如何優(yōu)化的更詳細的細節(jié),如緩存存儲本地化、內(nèi)存使用、退出策略、超時設(shè)定等。
一個能為DaoAuthenticationProvider提供存取認證庫的的類,它必須要實現(xiàn)UserDetailsService接口:
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;
UserDetails 是一個接口,它能提供一系列g(shù)et函數(shù)以獲得認證時需要的基本認證信息如用戶名、密碼、所獲得的授權(quán)、是否禁用等;一個具體的實現(xiàn)就是User類. Acegi用戶需要決定什么時候?qū)懰麄兊腢serDetailsService接口以及返回的UserDetails是什么類型。在大多數(shù)情況下將使用 User及其子類,雖然在特定的環(huán)境中(如對象關(guān)系映射器)也許需要用戶寫他們自己的UserDetails實現(xiàn)。UserDetails也經(jīng)常用于存儲一些與調(diào)用者相關(guān)的附加信息(如電話號碼、email地址等)因此它們經(jīng)常在web視圖中使用。
如果UserDetailsService實現(xiàn)起來很簡單,用戶應(yīng)當(dāng)很容易從他們選擇的持久化策略中找回認證信息。
DaoAuthenticationProvider設(shè)計沒有考慮支持帳戶鎖定的功能,因為那將增加UserDetailsService接口的復(fù)雜性。例如需要增加不成功認證的計數(shù),這些功能可能通過補充應(yīng)用程序的公布特性而很容易提供,這些特性將在下面討論。
DaoAuthenticationProvider 返回一個Authentication對象,它含有principal的屬性集。principal要么是一個字串(是必需的用戶名),要么是一個 UserDetails對象(從UserDetailsService中查找),缺省情況下返回UserDetails。因為這將使應(yīng)用能加上額外的屬性以便在應(yīng)用中使用,如用戶的全名,Email地址等。如使用容器適配器,或在應(yīng)用中使用Strings(在Acegi 0.6之前的版本就是這樣)你就應(yīng)在你的應(yīng)用上下文中把 DaoAuthenticationProvider.forcePrincipalAsString屬性設(shè)為true。
1.6.6 In-Memory 認證
雖然使用DaoAuthenticationProvider,從持久化引擎中獲取信息來創(chuàng)建定制的UserDetailsService實現(xiàn)很容易,但許多應(yīng)用不需要這么復(fù)雜,一種替代方式是使用InMemoryDaoImpl在應(yīng)用上下文中配置認證庫:
<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認證
1.6.8 JAAS認證
1.6.9 Siteminder認證
1.6.10 使用認證的幾點建議
---------------------------------------------------------------------------------------------------------------------------------
說人之短,乃護己之短。夸己之長,乃忌人之長。皆由存心不厚,識量太狹耳。能去此弊,可以進德,可以遠怨。
http://www.tkk7.com/szhswl
------------------------------------------------------------------------------------------------------ ----------------- ---------
posted on 2007-12-21 09:20
宋針還 閱讀(465)
評論(0) 編輯 收藏 所屬分類:
ACEGI