ACEGI安全框架應(yīng)用指南_第1頁
ACEGI安全框架應(yīng)用指南_第2頁
ACEGI安全框架應(yīng)用指南_第3頁
ACEGI安全框架應(yīng)用指南_第4頁
ACEGI安全框架應(yīng)用指南_第5頁
已閱讀5頁,還剩40頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

45/45ACEGI安全框架應(yīng)用指南級別:中級何平系統(tǒng)架構(gòu)師,獨(dú)立顧問,培訓(xùn)講師.2005年12月26日文章來源于一次acegi的項(xiàng)目應(yīng)用。因?yàn)闃I(yè)務(wù)需要與acegi框架缺省的應(yīng)用方式有一定的區(qū)別,故在實(shí)際應(yīng)用過程中嘗試了對acegi的一定量的改造工作,從而具有一定的研究和學(xué)習(xí)價(jià)值。文章中關(guān)于Acegi的介紹收入了其他文章中的內(nèi)容,已在參教資料中列出資料來源。內(nèi)容大綱:

認(rèn)識Acegi安全框架

安裝并運(yùn)行Acegi自帶的范例

改造Acegi框架滿足我們的業(yè)務(wù)要求

具體內(nèi)容:

認(rèn)識Acegi安全框架Acegi安全系統(tǒng),是一個(gè)用于SpringFramework的安全框架,能夠和目前流行的Web容器無縫集成.它使用了Spring的方式提供了安全和認(rèn)證安全服務(wù),包括使用BeanContext,攔截器和面向接口的編程方式.因此,Acegi安全系統(tǒng)能夠輕松地適用于復(fù)雜的安全需求。安全涉及到兩個(gè)不同的概念,認(rèn)證和授權(quán)。前者是關(guān)于確認(rèn)用戶是否確實(shí)是他們所宣稱的身份。授權(quán)則是關(guān)于確認(rèn)用戶是否有允許執(zhí)行一個(gè)特定的操作。

在Acegi安全系統(tǒng)中,需要被認(rèn)證的用戶,系統(tǒng)或代理稱為"Principal"。Acegi安全系統(tǒng)和其他的安全系統(tǒng)不同,它并沒有角色和用戶組的概念

關(guān)鍵組件Acegi安全系統(tǒng)包含以下七個(gè)關(guān)鍵的功能組件:lAuthentication對象,包含了Principal,Credential和Principal的授權(quán)信息.同時(shí)還可以包含關(guān)于發(fā)起認(rèn)證請求的客戶的其他信息,如IP地址。

2ContextHolder對象,使用ThreadLocal儲(chǔ)存Authentication對象的地方。

3AuthenticationManager,用于認(rèn)證ContextHolder中的Authentication對象。

4AccessDecissionManager,用于授權(quán)一個(gè)特定的操作。

5RunAsManager,當(dāng)執(zhí)行特定的操作時(shí),用于選擇性地替換Authentication對象.

6SecureObject攔截器,用于協(xié)調(diào)Authenticat(yī)ionManager,AccessDecissionManager,RunAsManager和特定操作的執(zhí)行.7ObjectDefinitionSource,包含了特定操作的授權(quán)定義.這七個(gè)關(guān)鍵的功能組件的關(guān)系如下圖所示(圖中灰色部分是關(guān)鍵組件):

安全管理對象Acegi安全系統(tǒng)目前支持兩類安全管理對象.

第一類的安全管理對象管理AOPAlliance的MethodInvocat(yī)ion,開發(fā)人員可以用它來保護(hù)Spring容器中的業(yè)務(wù)對象。為了使Spring管理的Bean可以作為MethodInvocation來使用,Bean可以通過ProxyFactoryBean和BeanNameAutoProxyCreator來管理,就像在Spring的事務(wù)管理一樣使用.

第二類是FilterInvocation。它用過濾器(Filter)來創(chuàng)建,并簡單地包裝了HTTP的ServletRequest,ServletResponse和FilterChain。FilterInvocation可以用來保護(hù)HTTP資源。通常,開發(fā)人員并不需要了解它的工作機(jī)制,因?yàn)樗麄冎恍枰獙ilter加入web.xml,Acegi安全系統(tǒng)就可以工作了.

安全配置參數(shù)每個(gè)安全管理對象都可以描述數(shù)量不限的各種安全認(rèn)證請求。例如,MethodInvocat(yī)ion對象可以描述帶有任意參數(shù)的任意方法的調(diào)用,而FilterInvocation可以描述任意的HTTPURL。

Acegi安全系統(tǒng)需要記錄應(yīng)用于每個(gè)認(rèn)證請求的安全配置參數(shù)。例如,對于BankManager.getBalance(intaccountNumber)方法和BankManager.a(chǎn)pproveLoan(intapplicationNumber)方法,它們需要的認(rèn)證請求的安全配置很不相同.

為了保存不同的認(rèn)證請求的安全配置,需要使用配置參數(shù)。從實(shí)現(xiàn)的視角來看,配置參數(shù)使用ConfigAttribute接口來表示。Acegi安全系統(tǒng)提供了ConfigAttribute接口的一個(gè)實(shí)現(xiàn),SecurityConfig,它把配置參數(shù)保存為一個(gè)字符串。

ConfigAttributeDefinition類是ConfigAttribute對象的一個(gè)簡單的容器,它保存了和特定請求相關(guān)的ConfigAttribute的集合。

當(dāng)安全攔截器收到一個(gè)安全認(rèn)證請求時(shí),需要決定應(yīng)用哪一個(gè)配置參數(shù)。換句話說,它需要找出應(yīng)用于這個(gè)請求的ConfigAttributeDefinition對象。這個(gè)查找的過程是由ObjectDefinitionSource接口來處理的。這個(gè)接口的主要方法是publicConfigAttributeDefinitiongetAttributes(Objectobject),其中Object參數(shù)是一個(gè)安全管理對象。因?yàn)榘踩芾韺ο蟀姓J(rèn)證請求的詳細(xì)信息,所以ObjectDefinitionSource接口的實(shí)現(xiàn)類可以從中獲得所需的詳細(xì)信息,以查找相關(guān)的ConfigAttributeDefiniton對象。

Acegi如何工作為了說明Acegi安全系統(tǒng)如何工作,我們設(shè)想一個(gè)使用Acegi的例子。通常,一個(gè)安全系統(tǒng)需要發(fā)揮作用,它必須完成以下的工作:

l首先,系統(tǒng)從客戶端請求中獲得Principal和Credential;

2然后系統(tǒng)認(rèn)證Principal和Credential信息;

3如果認(rèn)證通過,系統(tǒng)取出Principal的授權(quán)信息;

4接下來,客戶端發(fā)起操作請求;

5系統(tǒng)根據(jù)預(yù)先配置的參數(shù)檢查Principal對于該操作的授權(quán);6如果授權(quán)檢查通過則執(zhí)行操作,否則拒絕。

那么,Acegi安全系統(tǒng)是如何完成這些工作的呢?首先,我們來看看Acegi安全系統(tǒng)的認(rèn)證和授權(quán)的相關(guān)類圖:

圖中綠色部分是安全攔截器的抽象基類,它包含有兩個(gè)管理類,AuthenticationManager和AccessDecisionManager,如圖中灰色部分.AuthenticationManager用于認(rèn)證ContextHolder中的Authentication對象(包含了Principal,Credential和Principal的授權(quán)信息);AccessDecissionManager則用于授權(quán)一個(gè)特定的操作。下面來看一個(gè)MethodSecurityInterceptor的例子:<beanid="bankManagerSecurity”

class=”net。sf.a(chǎn)cegisecurity。intercept.method.MethodSecurityInterceptor”〉

〈propertyname="validat(yī)eConfigAttributes">

〈value>true〈/value>

〈/property〉

〈propertyname=”authenticationManager">

<refbean="authenticationManager"/〉

</property〉

〈propertyname="accessDecisionManager">

<refbean="accessDecisionManager"/>

</property>

〈propertyname="objectDefinitionSource">

〈value>

net。sf.acegisecurity.context。BankManager.delete*=

ROLE_SUPERVISOR,RUN_AS_SERVERnet。sf。acegisecurity。context。BankManager.getBalance=

ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_

</value>

</property>

</bean>上面的配置文件中,MethodSecurityInterceptor是AbstractSecurityInterceptor的一個(gè)實(shí)現(xiàn)類。它包含了兩個(gè)管理器,authenticationManager和accessDecisionManager。這兩者的配置如下:

〈beanid="authenticationDao"class="net.sf.a(chǎn)cegisecurity.providers。dao.jdbc.JdbcDaoImpl”>

<propertyname="dataSource">〈refbean=”dataSource”/>〈/property>

</bean〉

<beanid="daoAuthenticationProvider”

class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">

<propertyname="authenticationDao”><refbean=”authenticationDao"/〉</property>

</bean〉

<beanid=”authenticationManager"class="net.sf.a(chǎn)cegisecurity.providers.ProviderManager”>

<propertyname="providers”>

<list〉<refbean="daoAuthenticationProvider"/></list>

〈/property〉

</bean>

〈beanid=”roleVoter"class=”net.sf.acegisecurity.vote.RoleVoter”/>

〈beanid="accessDecisionManager"class=”net.sf.acegisecurity.vote.AffirmativeBased"〉

<propertyname="allowIfAllAbstainDecisions"〉〈value〉false</value></property>

〈propertyname="decisionVoters">

<list〉<refbean="roleVoter"/></list>

</property〉

</bean>

準(zhǔn)備工作做好了,現(xiàn)在我們來看看Acegi安全系統(tǒng)是如何實(shí)現(xiàn)認(rèn)證和授權(quán)機(jī)制的。以使用HTTPBASIC認(rèn)證的應(yīng)用為例子,它包括下面的步驟:1。

用戶登錄系統(tǒng),Acegi從acegisecurity.ui子系統(tǒng)的安全攔截器(如BasicProcessingFilter)中得到用戶的登錄信息(包括Principal和Credential)并放入Authentication對象,并保存在ContextHolder對象中;

2.安全攔截器將Authenticat(yī)ion對象交給AuthenticationManager進(jìn)行身份認(rèn)證,如果認(rèn)證通過,返回帶有Principal授權(quán)信息的Authenticat(yī)ion對象。此時(shí)ContextHolder對象的Authentication對象已擁有Principal的詳細(xì)信息;

3.用戶登錄成功后,繼續(xù)進(jìn)行業(yè)務(wù)操作;4.安全攔截器(bankManagerSecurity)收到客戶端操作請求后,將操作請求的數(shù)據(jù)包裝成安全管理對象(FilterInvocation或MethodInvocat(yī)ion對象);5.然后,從配置文件(ObjectDefinitionSource)中讀出相關(guān)的安全配置參數(shù)ConfigAttributeDefinition;6。接著,安全攔截器取出ContextHolder中的Authentication對象,把它傳遞給AuthenticationManager進(jìn)行身份認(rèn)證,并用返回值更新ContextHolder的Authentication對象;7。將Authenticat(yī)ion對象,ConfigAttributeDefinition對象和安全管理對象(secureObject)交給AccessDecisionManager,檢查Principal的操作授權(quán);

8。如果授權(quán)檢查通過則執(zhí)行客戶端請求的操作,否則拒絕;

AccessDecisionVoter注意上節(jié)的accessDecisionManager是一個(gè)AffirmativeBased類,它對于用戶授權(quán)的投票策略,只要通過其中的一個(gè)授權(quán)投票檢查,即可通過;它的allowIfAllAbstainDecisions屬性值是false,意思是如果所有的授權(quán)投票是都是棄權(quán),則通不過授權(quán)檢查。Acegi安全系統(tǒng)包括了幾個(gè)基于投票策略的AccessDecisionManager,上節(jié)的RoleVoter就是其中的一個(gè)投票策略實(shí)現(xiàn),它是AccessDecisionVoter的一個(gè)子類。AccessDecisionVoter的具體實(shí)現(xiàn)類通過投票來進(jìn)行授權(quán)決策,AccessDecisionManager則根據(jù)投票結(jié)果來決定是通過授權(quán)檢查,還是拋出AccessDeniedException例外。

AccessDecisionVoter接口共有三個(gè)方法:publicintvote(Authenticationauthenticat(yī)ion,Objectobject,ConfigAttributeDefinitionconfig);publicbooleansupports(ConfigAttributeat(yī)tribute);publicbooleansupports(Classclazz);其中的vote方法返回int返回值,它們是AccessDecisionVoter的三個(gè)靜態(tài)成員屬性:ACCESS_ABSTAIN,,ACCESS_DENIED和ACCESS_GRANTED,它們分別是棄權(quán),否決和贊成。Acegi安全系統(tǒng)中,使用投票策略的AccessDecisionManager共有三個(gè)具體實(shí)現(xiàn)類:AffirmativeBased、ConsensusBased和UnanimousBased.它們的投票策略是,AffirmativeBased類只需有一個(gè)投票贊成即可通過;ConsensusBased類需要大多數(shù)投票贊成即可通過;而UnanimousBased類需要所有的投票贊成才能通過。RoleVoter類是一個(gè)Acegi安全系統(tǒng)AccessDecisionVoter接口的實(shí)現(xiàn).如果ConfigAttribute以ROLE_開頭,RoleVoter則進(jìn)行投票.如果GrantedAuthority的getAutority方法的String返回值匹配一個(gè)或多個(gè)以ROLE_開頭的ConfigAttribute,則投票通過,否則不通過。如果沒有以ROLE_開頭的ConfigAttribute,RoleVoter則棄權(quán)。

小結(jié)到這里,我想各位對于Acegi安全框架的實(shí)現(xiàn)原理和運(yùn)行機(jī)制已經(jīng)有了較清楚的認(rèn)識.下一步我們就理論聯(lián)系實(shí)踐來感覺一下Acegi給我們帶來樂趣。

安裝并運(yùn)行acegi自帶的范例為了讓大家對acegi有一個(gè)感性的認(rèn)識,下面我們一起來安裝Acegi自帶的demo,并運(yùn)行它,親身感覺Acegi都為我們帶來了些什么。

需要的軟件Acegi0。83版本注意,目前Acegi的發(fā)布版本還不是很穩(wěn)定,如果大家要運(yùn)行我后面提供的范列,最好是下載這個(gè)版本的。下載地址:

因?yàn)槲覀冞€需求分析它的源碼,所以最好也下之

Tomcat5.5下載地址:

J2SE5。0下載地址:

安裝范例1.

安裝tomcat到合適的位置2.

解壓acegi—security—0.8.3.zip,目錄展開如下:

圖中選中的文件就是我們將安裝的demo.

3。

將acegi—security-sample-contacts—filter.war復(fù)制到tomcat/webapps目錄下4。

啟動(dòng)tomcat5.

通過地址:訪問demo界面如下:6.

打開上面的頁面后,大家就可以親身去體驗(yàn)Acegi為我們來了什么.

提示其實(shí)只要好好研究一下這個(gè)demo中對于Acegi的用法,基本上就可以掌握Acegi了.一起加油吧.

改造Acegi框架滿足我們的業(yè)務(wù)要求

我們的Acegi的范例在前面介紹Acegi時(shí),我們舉例說明了Acegi是如何做到對業(yè)務(wù)對象的訪問控制的。在更多的時(shí)候,對于Web應(yīng)用程序還要控制頁面的訪問。而我們的業(yè)務(wù)要求就是這樣的簡單,根據(jù)不同的角色決定它能訪問哪些頁面和哪些對象的哪些方法.目前暫時(shí)不考慮具體角色的具體權(quán)限指派,關(guān)于這部分內(nèi)容大家可以通過研究demo獲得相應(yīng)的知識。因?yàn)槭桥e例說明Acegi的用法,現(xiàn)假設(shè)我們的web工程名為myacegi,其目錄結(jié)構(gòu)如下:

其中的secure目錄下的文件就是我們希望受控制的頁面.

src目錄是我們的java源程序。

acegilogin.jsp是我們的登錄界面.

logoff.jsp是我們的登出頁面。

test.jsp頁面中有我們對受控業(yè)務(wù)對象的受控方法的訪問舉例。

WEB-INF目錄下的目錄結(jié)構(gòu)如下:

classes和lib目錄就不再解釋了

applicationContext-common-business.xml配置了例子中要使用的數(shù)據(jù)源

applicationContext-acegi-security.xml配置了例子中關(guān)于安全方面的內(nèi)容

applicat(yī)ionContext—common-authorizat(yī)ion。xml配置了例子中關(guān)于授權(quán)方面的內(nèi)容

web.xml當(dāng)然就是整個(gè)web應(yīng)用的配置了。我們在這里先詳細(xì)說明一下web.xml文件,其它的配置文件的內(nèi)容將在后面的改造過程中不斷深入web.xml文件內(nèi)容如下:

〈?xmlversion="1.0"encoding=”UTF-8”?〉<!DOCTYPEweb-appPUBLIC’-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN''’〉

<web-app>

〈display-name>myacegiexample〈/display—name>

〈context-param>

<param—name>contextConfigLocat(yī)ion〈/param—name>

<param—value>

/WEB—INF/applicationContext—acegi—security。xml

/WEB—INF/applicationContext—common—business。xml

/WEB—INF/applicationContext—common—authorization.xml

〈/param-value>

</context-param>

〈filter>

<filter—name〉A(chǔ)cegiFilterChainProxy</filter-name>

<filter-class〉

net.sf.acegisecurity。util.FilterToBeanProxy

</filter-class〉

〈init-param>

<param-name>targetClass</param-name>

〈param-value>

net。sf.acegisecurity。util。FilterChainProxy

〈/param—value>

</init—param〉

</filter〉

<filter-mapping>

<filter-name>AcegiFilterChainProxy〈/filter—name>

<url-pattern〉/*</url-pattern>

</filter-mapping〉

<listener>

<listener-class>

org.springframework.web.context。ContextLoaderListener

</listener-class>

〈/listener>

〈listener>

<listener-class>

net.sf。acegisecurity.ui.session.HttpSessionEventPublisher

</listener-class〉

〈/listener〉

〈welcome-〉

<welcome—</welcome-file〉

</welcome—〉

<taglib>

<taglib—uri>/spring</taglib-uri>

〈taglib-location>/WEB—INF/spring.tld</taglib-location>

</taglib>

</web-app>

在上面的配置中,我只說明與Acegi有直接關(guān)系的部分1。

定義了一個(gè)應(yīng)用程序域的變量contextConfigLocation

〈context—param>

<param-name>contextConfigLocation〈/param—name>

〈param-value〉

/WEB—INF/applicationContext-acegi—security。xml

/WEB—INF/applicat(yī)ionContext-common—business.xml

/WEB—INF/applicationContext-common—authorization。xml

</param—value〉

〈/context—param>

這里列出了我們希望Spring框架(Acegi中已經(jīng)自帶的Spring)加載的關(guān)于Acegi的配置文件。

2.

定義了一個(gè)過濾器AcegiFilterChainProxy,〈filter>

<filter-name>AcegiFilterChainProxy〈/filter—name>

<filter—class>

net。sf。acegisecurity.util.FilterToBeanProxy

</filter-class>

<init-param>

<param—name>targetClass</param—name〉

<param-value>

net。sf.a(chǎn)cegisecurity.util.FilterChainProxy

〈/param-value>

〈/init—param〉

</filter>

〈filter—mapping〉

<filter—name〉A(chǔ)cegiFilterChainProxy</filter—name>

<url—pat(yī)tern〉/*</url—pattern>

〈/filter—mapping>這樣的配置表時(shí),當(dāng)前web應(yīng)用中的所用url的請求訪問都會(huì)被這個(gè)過濾器捕獲,也就是說,Acegi的頁面控制其實(shí)和我們平時(shí)的開發(fā)一樣,也是通過過濾器來實(shí)現(xiàn)的。

3.定義了兩個(gè)監(jiān)聽器〈listener>

〈listener-class>

org.springframework.web.context.ContextLoaderListener

〈/listener-class〉

</listener>

<listener〉

<listener—class>

net。sf。acegisecurity.ui.session。HttpSessionEventPublisher

</listener—class>

</listener>

第一個(gè)是用來動(dòng)態(tài)加載我們前面定義的應(yīng)用程序域的變量contextConfigLocation中所列出的配置文件的,第二個(gè)是Acegi內(nèi)部需求使用的事件發(fā)布器,我們不需求太多關(guān)心它的實(shí)現(xiàn)和用法,就這樣放著吧.

總的來說,這個(gè)工程本身也是以demo程序作為樣板來建立的。

想了解更多信息,建議下載范例代碼。

改造schema通過Acegi的demo演示大家可以看到,它所提供的缺省用戶驗(yàn)證辦法是依據(jù)的用戶名和登錄密碼,而對于授權(quán)訪問方面是根據(jù)用戶所付于的角色來進(jìn)行判斷的。但在我們的業(yè)務(wù)系統(tǒng)中,用戶驗(yàn)證則有所不同。單位號、用戶ID和登錄密碼三者放在一起才能驗(yàn)證一個(gè)用戶。同樣對于用戶角色的查詢辦法也得變成以單位號加用戶ID為條件。我們先來看看Acegi所提供的demo的表結(jié)構(gòu)和表間關(guān)系.

CREATETABLEusers(

usernameVARCHAR(50)NOTNULLPRIMARYKEY,

passwordVARCHAR(50)NOTNULL,

enabledBITNOTNULL

);

CREATETABLEauthorities(

usernameVARCHAR(50)NOTNULL,

authorityVARCHAR(50)NOTNULL

);

CREATEUNIQUEINDEXix_auth_usernameONauthorities(username,authority);

CREATETABLEacl_object_identity(

idBIGINTGENERATEDBYDEFAULTASIDENTITY(STARTWITH0)NOTNULLPRIMARYKEY,

object_identityVARCHAR_IGNORECASE(250)NOTNULL,

parent_objectBIGINT,

acl_classVARCHAR_IGNORECASE(250)NOTNULL,

CONSTRAINTunique_object_identityUNIQUE(object_identity),

FOREIGNKEY(parent_object)REFERENCESacl_object_identity(id)

);

CREATETABLEacl_permission(

idBIGINTGENERATEDBYDEFAULTASIDENTITY(STARTWITH0)

NOTNULLPRIMARYKEY

acl_object_identityBIGINTNOTNULL,

recipientVARCHAR_IGNORECASE(100)NOTNULL,

maskINTEGERNOTNULL,

CONSTRAINTunique_recipientUNIQUE(acl_object_identity,recipient),

FOREIGNKEY(acl_object_identity)REFERENCESacl_object_identity(id)

);

注意:以上sql語句來源于Acegi網(wǎng)站,應(yīng)用于hsql。網(wǎng)頁地址:

通過上面的schema可以看出Acegi是如何管理用戶和進(jìn)行授權(quán)的。也就是說,如果要讓其滿足我們前面所提出的業(yè)務(wù)要求,第一步從schema這塊就得進(jìn)行改造。

我們業(yè)務(wù)上的實(shí)際要求很簡單,還沒有涉及到對象的方法訪問的權(quán)限問題,只是想根據(jù)用戶的角色來控制其頁面和業(yè)務(wù)方法的調(diào)用。從而得到我們所需要的schema。

CREATETABLERS

(DWHvarchar(2)NOTNULL,

USER_IDvarchar(5)NOTNULL,

USER_NAMEvarchar(20),

ENABLEDvarchar(1)

,PRIMARYKEY(DWH,

XTBH,USER_ID));

CREATETABLEdbo.a(chǎn)uthorities

(DWHvarchar(2)NOTNULL,

USER_IDvarchar(5)NOTNULL,

authorityvarchar(50)NOTNULL

,PRIMARYKEY(DWH,

USER_ID,authority));

注意:以上sql語法為odbc格式。

到此,schema的改造完成,趕快到我們的數(shù)據(jù)庫中實(shí)施它們吧。

改造登錄頁面我們要求,如果客戶訪問了我們聲明要控制的頁面,則將請求定位到登錄頁面,要求客戶通過登錄操作向系統(tǒng)表明自己的身份。下面就是我們在系統(tǒng)中使用的登錄界面,它合demo自帶的那個(gè)只有一點(diǎn)點(diǎn)區(qū)別,demo自帶的那個(gè)只有用戶名和登錄密碼兩個(gè)字段,而我們的是單位號、用戶ID和登錄密碼三個(gè)字段。頁面最重要的源碼如下:

<formaction=”<c:urlvalue=’j_acegi_security_check’/>"method="POST"〉

<table>

〈tr><td〉單位號:〈/td〉〈td><inputtype=’text'name='j_dwh'></td〉</tr>

<tr〉〈td>用戶ID:</td><td〉〈inputtype='text'name='j_userid'〉</td>〈/tr>

〈tr〉<td>登錄密碼:</td><td〉<inputtype='password’name=’j_password’></td〉</tr>

<tr〉〈tdcolspan='2’〉〈inputname="submit"type=”submit”〉</td>〈/tr>

<tr〉〈tdcolspan='2'><=”reset"type="reset"></td></tr>

〈/table>

</form〉大家可以看出,這個(gè)頁面其實(shí)沒有什么特別之處,只是根據(jù)我們的業(yè)務(wù)要求修改表單的定義罷了。有一點(diǎn)要注意的是Action的值是j_acegi_security_check,這個(gè)值我們將在applicat(yī)ionContext-acegi—security.xml給出定義之所在,也就是說這里只是引用罷了。另外還有一點(diǎn)要注意的就是其中的三個(gè)字段值:j_dwh、j_userid、j_password在后面的Acegi的代碼改造中要用到的

applicationContext—acegi—security。xml配置說明及其實(shí)現(xiàn)先看看整體內(nèi)容:〈beans>

<!--========================FILTERCHAIN=======================--〉

<beanid="filterChainProxy"

class="net.sf。acegisecurity。util。FilterChainProxy”〉

〈propertyname=”filterInvocationDefinitionSource">

〈value>

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

PATTERN_TYPE_APACHE_ANT

/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter

</value〉

〈/property〉

〈/bean>

〈!-—========================AUTHENTICATION=======================——>

<beanid="authenticationManager"

class="net.sf.acegisecurity.providers。ProviderManager”>

〈propertyname=”providers”>

<list>

〈reflocal=”daoAuthenticationProvider"/〉

<reflocal=”anonymousAuthenticationProvider"/〉

</list>

</property〉

〈/bean>

<beanid=”userDAO”class="erDAO"〉

<propertyname="dataSource">

〈refbean=”dat(yī)aSource"/〉

〈/property>

〈/bean〉

〈beanid="cacheManager"

class="che.ehcache.EhCacheManagerFactoryBean”/>

〈beanid="userCacheBackend”

class="che。ehcache.EhCacheFactoryBean">

〈propertyname="cacheManager”>

〈reflocal=”cacheManager”/>

</property>

<propertyname=”cacheName">

<value>userCache〈/value>

〈/property>

〈/bean〉

<beanid="userCache”

class=”che.EhCacheBasedUserCache">

<propertyname="cache”>

〈reflocal="userCacheBackend"/>

</property>

</bean>

〈beanid=”daoAuthenticationProvider”

class="com。cqkyinfo.ydxt.acegi.dao。PasswordDaoAuthenticationProvider”〉

〈propertyname=”authenticationDao">

<reflocal="userDAO"/>

</property〉

<propertyname=”userCache">

<reflocal=”userCache”/>

</property>

〈/bean>

<!--AutomaticallyreceivesAuthenticationEventmessagesfromDaoAuthenticationProvider—->

〈beanid="loggerListener”

class="net.sf.a(chǎn)cegisecurividers.dao。event。LoggerListener"/>

<beanid="basicProcessingFilter"

class="net.sf.a(chǎn)cegisecurity.ui.basicauth.BasicProcessingFilter”>

<propertyname=”authenticationManager”>

〈reflocal="authenticationManager"/>

</property>

〈propertyname="authenticationEntryPoint">

〈reflocal=”basicProcessingFilterEntryPoint”/>

</property〉

〈/bean>

<beanid=”basicProcessingFilterEntryPoint"

class=”net。sf。acegisecurity。ui。basicauth.BasicProcessingFilterEntryPoint”〉

<propertyname="realmName">

<value〉ContactsRealm</value〉

</property>

</bean〉

<beanid=”anonymousProcessingFilter"

class="net.sf.a(chǎn)cegisecurity.providers.anonymous.AnonymousProcessingFilter">

<propertyname="key">

〈value>foobar〈/value〉

〈/property>

<propertyname="userAttribute”>

<value>anonymousUser,ROLE_ANONYM(fèi)OUS〈/value〉

</property>

</bean〉

<beanid=”anonymousAuthenticationProvider"

class=”net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">

<propertyname="key">

<value〉foobar〈/value>

</property>

</bean>

<beanid=”httpSessionContextIntegrationFilter"

class="net.sf.acegisecurity。context.HttpSessionContextIntegrationFilter”>

〈propertyname="context"〉

<value>

net。sf。acegisecurity.context。security.SecureContextImpl

〈/value>

〈/property>

</bean>

<!——=====================HTTPREQUESTSECURITY====================—->

<beanid="securityEnforcementFilter"

class="net.sf.a(chǎn)cegisecurity.intercept。web。SecurityEnforcementFilter”>

〈propertyname="filterSecurityInterceptor"〉

<reflocal=”filterInvocationInterceptor"/〉

〈/property>

〈propertyname="authenticationEntryPoint”〉

〈reflocal=”authenticationProcessingFilterEntryPoint"/>

</property〉

</bean>

〈beanid=”authenticationProcessingFilter”

class="com。cqkyinfo.ydxt.acegi.ui。webapp.AuthenticationProcessingFilter”〉

<propertyname="authenticationManager">

〈refbean="authenticationManager"/〉

〈/property>

〈propertyname="authenticationFailureUrl">

〈value>/acegilogin。jsp?login_error=1〈/value〉

〈/property>

〈propertyname="defaultTargetUrl”〉

〈value〉/〈/value〉

</property〉

<propertyname=”filterProcessesUrl”>

<value>/j_acegi_security_check</value>

</property〉

</bean〉

<beanid="authenticationProcessingFilterEntryPoint”

class="net。sf。acegisecurity。ui.webapp.Authenticat(yī)ionProcessingFilterEntryPoint">

〈propertyname=”loginFormUrl">

〈value〉/acegilogin。jsp</value〉

</property>

<propertyname="forceHttps”>

<value〉false〈/value〉

</property〉

〈/bean>

〈beanid="httpRequestAccessDecisionManager"

class="net.sf.acegisecurity。vote.AffirmativeBased”>

〈propertyname="allowIfAllAbstainDecisions">

〈value>false</value〉

〈/property>

<propertyname="decisionVoters"〉

<list>

<refbean=”roleVoter"/>

</list〉

〈/property〉

</bean>

〈!——NotetheorderthatentriesareplacedagainsttheobjectDefinitionSourceiscritical.

TheFilterSecurityInterceptorwillworkfromthetopofthelistdowntotheFIRSTpatternthatmatchestherequestURL.

Accordingly,youshouldplaceMOSTSPECIFIC(iea/b/c/d.*)expressionsfirst,withLEASTSPECIFIC(iea/.*)expressionslast—->

<beanid="filterInvocationI(lǐng)nterceptor”

class="net.sf.acegercept。web.FilterSecurityInterceptor”〉

〈propertyname="authenticationManager">

<refbean="authenticat(yī)ionManager”/〉

</property>

〈propertyname="accessDecisionManager”〉

〈reflocal="httpRequestAccessDecisionManager"/>

</property>

<propertyname=”objectDefinitionSource">

<value>

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

PATTERN_TYPE_APACHE_ANT

/index.jsp=ROLE_ANONYMOUS,ROLE_SUPERVISOR

/logoff.jsp=ROLE_ANONYMOUS,ROLE_SUPERVISOR

/acegilogin。jsp*=ROLE_ANONYMOUS,ROLE_SUPERVISOR

/**=ROLE_SUPERVISOR

</value>

〈/property>

</bean>

〈/beans>1.

FILTERCHAIN定義了beanfilterChainProxy,需求說明的部分是屬性filterInvocat(yī)ionDefinitionSource的值/**=httpSessionContextIntegrat(yī)ionFilter,authenticat(yī)ionProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter它表時(shí)我們的過濾器將引用的一系列Acegi服務(wù)。2。

AUTHENTICATION定義了:a)

authenticationManager,也就是認(rèn)證管理器,這個(gè)在介紹部分有說明。它的providers屬性我們在這里指定了兩個(gè):

i.

一個(gè)是用于數(shù)據(jù)庫認(rèn)證的daoAuthenticationProviderbean

ii。

一個(gè)是用于匿名訪問的anonymousAuthenticationProvider

b)

userDAO,這個(gè)bean是我們自己所改造的,實(shí)現(xiàn)了我們前面說定義的schema中users表和authorities表的訪問.在demo中,這個(gè)對象叫做jdbcDaoImpl,而且是使用的Acegi的自己的實(shí)現(xiàn),大家要注意一下。詳情見源碼。

packagecom.cqkyinfo。ydxt。acegi.dao;

importjava。sql。ResultSet;importjava.sql.SQLException;importjava.sql.Types;importjava.util。List;

importjavax.sql.DataSource;

importnet.sf。acegisecurity.BadCredentialsException;importnet。sf.a(chǎn)cegisecurity.GrantedAuthority;importnet.sf。acegisecurity.GrantedAuthorityImpl;imporernameNotFoundException;

importorg。springframework。dao.Dat(yī)aAccessException;importorg.springframework。jdbc.core.SqlParameter;importorg。springframework。jdbc。core.support.JdbcDaoSupport;importorg.springframework.jdbc。object。MappingSqlQuery;

importcom.cqkyinfo.ydxt.acegi.IUser;imporer;importcom。cqkyinfo。ydxt.base.datavisitor。DTO;importcom.cqkyinfo.ydxt.exceptions.BusinessException;importcom。cqkyinfo。ydxt。xtgl.business。XTGLBLFacade;

publicclassUserDAOextendsJdbcDaoSupportimplements

PasswordAuthenticationDao{

publicstaticfinalStringDEF_AUTHORITIES_BY_DWH_AND_USERID_QUERY="SELECTdwh,user_id,authorityFROMauthoritiesWHEREdwh=?ANDuser_id=?";

privat(yī)eMappingSqlQueryauthoritiesByDwhAndUseridMapping;

publicUserDAO(){

super();

}

publicIUserloadUserByDwhAndUseridAndPassword(Stringdwh,Stringuserid,

Stringpassword)throwsDataAccessException,

BadCredentialsException{

Useruser=null;

try{

DTOdto=XTGLBLFacade.getInstance().getUserManager().getLoginUser(

dwh,userid,password);

StringenabledStr=dto.getValue(”enabled”).toString();

booleanenabled=false;

if(enabledStr.equals("1”)){

enabled=true;

authoritiesByDwhAndUseridMapping=newAuthoritiesByDwhAndUseridMapping(

getDataSource());

ListdbAuths=authoritiesByDwhAndUseridMapping

.execute(newString[]{dwh,userid});

if(dbAuths.size()==0){

thrownewRuntimeException(”UserhasnoGrantedAuthority”);

}

GrantedAuthority[]arrayAuths={};

arrayAuths=(GrantedAuthority[])dbAuths。toArray(arrayAuths);

user=newUser(dwh,userid,password,enabled,true,true,true,

arrayAuths);

}catch(BusinessExceptione){

logger.error(e.getMessage());

}

returnuser;

}

/**

*Queryobjecttolookupauser’sauthorities.

*/

protectedclassAuthoritiesByDwhAndUseridMappingextendsMappingSqlQuery{

protectedAuthoritiesByDwhAndUseridMapping(DataSourceds){

super(ds,DEF_AUTHORITIES_BY_DWH_AND_USERID_QUERY);

declareParameter(newSqlParameter(Types.VARCHAR));

declareParameter(newSqlParameter(Types.VARCHAR));

compile();

protectedObjectmapRow(ResultSetrs,intrownum)throwsSQLException{

StringroleName=rs。getString(3);

GrantedAuthorityImplauthority=newGrantedAuthorityImpl(roleName);

returnauthority;

}

c)

cacheManager和userCacheBackend,這兩大家一看就知道,我也是用的Acegi的實(shí)現(xiàn).

d)

userCache是我們自己改造的,原因是demo中是以username為標(biāo)識來區(qū)別被緩存的對象的,而我們是dwh+userid.

詳情見源碼。packagche;

imporche;imporcheException;importnet。sf.ehcache。Element;

impormons。logging.Log;impormons.logging.LogFactory;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.dao.DataRetrievalFailureException;

impo.cqkyinfo.ydxt.acegi。IUser;

publicclassEhCacheBasedUserCacheimplementsUserCache,InitializingBean{

//~Staticfields/initializers=============================================

privatestaticfinalLoglogger=LogFactory.getLog(EhCacheBasedUserCache.class);

//~Instancefields========================================================

privateCachecache;

//~Methods====================

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論