




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
45/45ACEGI安全框架應(yīng)用指南級(jí)別:中級(jí)何平系統(tǒng)架構(gòu)師,獨(dú)立顧問(wèn),培訓(xùn)講師.2005年12月26日文章來(lái)源于一次acegi的項(xiàng)目應(yīng)用。因?yàn)闃I(yè)務(wù)需要與acegi框架缺省的應(yīng)用方式有一定的區(qū)別,故在實(shí)際應(yīng)用過(guò)程中嘗試了對(duì)acegi的一定量的改造工作,從而具有一定的研究和學(xué)習(xí)價(jià)值。文章中關(guān)于Acegi的介紹收入了其他文章中的內(nèi)容,已在參教資料中列出資料來(lái)源。內(nèi)容大綱:
認(rèn)識(shí)Acegi安全框架
安裝并運(yùn)行Acegi自帶的范例
改造Acegi框架滿足我們的業(yè)務(wù)要求
具體內(nèi)容:
認(rèn)識(shí)Acegi安全框架Acegi安全系統(tǒng),是一個(gè)用于SpringFramework的安全框架,能夠和目前流行的Web容器無(wú)縫集成.它使用了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)不同,它并沒(méi)有角色和用戶組的概念
關(guān)鍵組件Acegi安全系統(tǒng)包含以下七個(gè)關(guān)鍵的功能組件:lAuthentication對(duì)象,包含了Principal,Credential和Principal的授權(quán)信息.同時(shí)還可以包含關(guān)于發(fā)起認(rèn)證請(qǐng)求的客戶的其他信息,如IP地址。
2ContextHolder對(duì)象,使用ThreadLocal儲(chǔ)存Authentication對(duì)象的地方。
3AuthenticationManager,用于認(rèn)證ContextHolder中的Authentication對(duì)象。
4AccessDecissionManager,用于授權(quán)一個(gè)特定的操作。
5RunAsManager,當(dāng)執(zhí)行特定的操作時(shí),用于選擇性地替換Authentication對(duì)象.
6SecureObject攔截器,用于協(xié)調(diào)Authenticat(yī)ionManager,AccessDecissionManager,RunAsManager和特定操作的執(zhí)行.7ObjectDefinitionSource,包含了特定操作的授權(quán)定義.這七個(gè)關(guān)鍵的功能組件的關(guān)系如下圖所示(圖中灰色部分是關(guān)鍵組件):
安全管理對(duì)象Acegi安全系統(tǒng)目前支持兩類安全管理對(duì)象.
第一類的安全管理對(duì)象管理AOPAlliance的MethodInvocat(yī)ion,開發(fā)人員可以用它來(lái)保護(hù)Spring容器中的業(yè)務(wù)對(duì)象。為了使Spring管理的Bean可以作為MethodInvocation來(lái)使用,Bean可以通過(guò)ProxyFactoryBean和BeanNameAutoProxyCreator來(lái)管理,就像在Spring的事務(wù)管理一樣使用.
第二類是FilterInvocation。它用過(guò)濾器(Filter)來(lái)創(chuàng)建,并簡(jiǎn)單地包裝了HTTP的ServletRequest,ServletResponse和FilterChain。FilterInvocation可以用來(lái)保護(hù)HTTP資源。通常,開發(fā)人員并不需要了解它的工作機(jī)制,因?yàn)樗麄冎恍枰獙ilter加入web.xml,Acegi安全系統(tǒng)就可以工作了.
安全配置參數(shù)每個(gè)安全管理對(duì)象都可以描述數(shù)量不限的各種安全認(rèn)證請(qǐng)求。例如,MethodInvocat(yī)ion對(duì)象可以描述帶有任意參數(shù)的任意方法的調(diào)用,而FilterInvocation可以描述任意的HTTPURL。
Acegi安全系統(tǒng)需要記錄應(yīng)用于每個(gè)認(rèn)證請(qǐng)求的安全配置參數(shù)。例如,對(duì)于BankManager.getBalance(intaccountNumber)方法和BankManager.a(chǎn)pproveLoan(intapplicationNumber)方法,它們需要的認(rèn)證請(qǐng)求的安全配置很不相同.
為了保存不同的認(rèn)證請(qǐng)求的安全配置,需要使用配置參數(shù)。從實(shí)現(xiàn)的視角來(lái)看,配置參數(shù)使用ConfigAttribute接口來(lái)表示。Acegi安全系統(tǒng)提供了ConfigAttribute接口的一個(gè)實(shí)現(xiàn),SecurityConfig,它把配置參數(shù)保存為一個(gè)字符串。
ConfigAttributeDefinition類是ConfigAttribute對(duì)象的一個(gè)簡(jiǎn)單的容器,它保存了和特定請(qǐng)求相關(guān)的ConfigAttribute的集合。
當(dāng)安全攔截器收到一個(gè)安全認(rèn)證請(qǐng)求時(shí),需要決定應(yīng)用哪一個(gè)配置參數(shù)。換句話說(shuō),它需要找出應(yīng)用于這個(gè)請(qǐng)求的ConfigAttributeDefinition對(duì)象。這個(gè)查找的過(guò)程是由ObjectDefinitionSource接口來(lái)處理的。這個(gè)接口的主要方法是publicConfigAttributeDefinitiongetAttributes(Objectobject),其中Object參數(shù)是一個(gè)安全管理對(duì)象。因?yàn)榘踩芾韺?duì)象包含有認(rèn)證請(qǐng)求的詳細(xì)信息,所以ObjectDefinitionSource接口的實(shí)現(xiàn)類可以從中獲得所需的詳細(xì)信息,以查找相關(guān)的ConfigAttributeDefiniton對(duì)象。
Acegi如何工作為了說(shuō)明Acegi安全系統(tǒng)如何工作,我們?cè)O(shè)想一個(gè)使用Acegi的例子。通常,一個(gè)安全系統(tǒng)需要發(fā)揮作用,它必須完成以下的工作:
l首先,系統(tǒng)從客戶端請(qǐng)求中獲得Principal和Credential;
2然后系統(tǒng)認(rèn)證Principal和Credential信息;
3如果認(rèn)證通過(guò),系統(tǒng)取出Principal的授權(quán)信息;
4接下來(lái),客戶端發(fā)起操作請(qǐng)求;
5系統(tǒng)根據(jù)預(yù)先配置的參數(shù)檢查Principal對(duì)于該操作的授權(quán);6如果授權(quán)檢查通過(guò)則執(zhí)行操作,否則拒絕。
那么,Acegi安全系統(tǒng)是如何完成這些工作的呢?首先,我們來(lái)看看Acegi安全系統(tǒng)的認(rèn)證和授權(quán)的相關(guān)類圖:
圖中綠色部分是安全攔截器的抽象基類,它包含有兩個(gè)管理類,AuthenticationManager和AccessDecisionManager,如圖中灰色部分.AuthenticationManager用于認(rèn)證ContextHolder中的Authentication對(duì)象(包含了Principal,Credential和Principal的授權(quán)信息);AccessDecissionManager則用于授權(quán)一個(gè)特定的操作。下面來(lái)看一個(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)在我們來(lái)看看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對(duì)象,并保存在ContextHolder對(duì)象中;
2.安全攔截器將Authenticat(yī)ion對(duì)象交給AuthenticationManager進(jìn)行身份認(rèn)證,如果認(rèn)證通過(guò),返回帶有Principal授權(quán)信息的Authenticat(yī)ion對(duì)象。此時(shí)ContextHolder對(duì)象的Authentication對(duì)象已擁有Principal的詳細(xì)信息;
3.用戶登錄成功后,繼續(xù)進(jìn)行業(yè)務(wù)操作;4.安全攔截器(bankManagerSecurity)收到客戶端操作請(qǐng)求后,將操作請(qǐng)求的數(shù)據(jù)包裝成安全管理對(duì)象(FilterInvocation或MethodInvocat(yī)ion對(duì)象);5.然后,從配置文件(ObjectDefinitionSource)中讀出相關(guān)的安全配置參數(shù)ConfigAttributeDefinition;6。接著,安全攔截器取出ContextHolder中的Authentication對(duì)象,把它傳遞給AuthenticationManager進(jìn)行身份認(rèn)證,并用返回值更新ContextHolder的Authentication對(duì)象;7。將Authenticat(yī)ion對(duì)象,ConfigAttributeDefinition對(duì)象和安全管理對(duì)象(secureObject)交給AccessDecisionManager,檢查Principal的操作授權(quán);
8。如果授權(quán)檢查通過(guò)則執(zhí)行客戶端請(qǐng)求的操作,否則拒絕;
AccessDecisionVoter注意上節(jié)的accessDecisionManager是一個(gè)AffirmativeBased類,它對(duì)于用戶授權(quán)的投票策略,只要通過(guò)其中的一個(gè)授權(quán)投票檢查,即可通過(guò);它的allowIfAllAbstainDecisions屬性值是false,意思是如果所有的授權(quán)投票是都是棄權(quán),則通不過(guò)授權(quán)檢查。Acegi安全系統(tǒng)包括了幾個(gè)基于投票策略的AccessDecisionManager,上節(jié)的RoleVoter就是其中的一個(gè)投票策略實(shí)現(xiàn),它是AccessDecisionVoter的一個(gè)子類。AccessDecisionVoter的具體實(shí)現(xiàn)類通過(guò)投票來(lái)進(jìn)行授權(quán)決策,AccessDecisionManager則根據(jù)投票結(jié)果來(lái)決定是通過(guò)授權(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è)投票贊成即可通過(guò);ConsensusBased類需要大多數(shù)投票贊成即可通過(guò);而UnanimousBased類需要所有的投票贊成才能通過(guò)。RoleVoter類是一個(gè)Acegi安全系統(tǒng)AccessDecisionVoter接口的實(shí)現(xiàn).如果ConfigAttribute以ROLE_開頭,RoleVoter則進(jìn)行投票.如果GrantedAuthority的getAutority方法的String返回值匹配一個(gè)或多個(gè)以ROLE_(tái)開頭的ConfigAttribute,則投票通過(guò),否則不通過(guò)。如果沒(méi)有以ROLE_開頭的ConfigAttribute,RoleVoter則棄權(quán)。
小結(jié)到這里,我想各位對(duì)于Acegi安全框架的實(shí)現(xiàn)原理和運(yùn)行機(jī)制已經(jīng)有了較清楚的認(rèn)識(shí).下一步我們就理論聯(lián)系實(shí)踐來(lái)感覺(jué)一下Acegi給我們帶來(lái)樂(lè)趣。
安裝并運(yùn)行acegi自帶的范例為了讓大家對(duì)acegi有一個(gè)感性的認(rèn)識(shí),下面我們一起來(lái)安裝Acegi自帶的demo,并運(yùn)行它,親身感覺(jué)Acegi都為我們帶來(lái)了些什么。
需要的軟件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.
通過(guò)地址:訪問(wèn)demo界面如下:6.
打開上面的頁(yè)面后,大家就可以親身去體驗(yàn)Acegi為我們來(lái)了什么.
提示其實(shí)只要好好研究一下這個(gè)demo中對(duì)于Acegi的用法,基本上就可以掌握Acegi了.一起加油吧.
改造Acegi框架滿足我們的業(yè)務(wù)要求
我們的Acegi的范例在前面介紹Acegi時(shí),我們舉例說(shuō)明了Acegi是如何做到對(duì)業(yè)務(wù)對(duì)象的訪問(wèn)控制的。在更多的時(shí)候,對(duì)于Web應(yīng)用程序還要控制頁(yè)面的訪問(wèn)。而我們的業(yè)務(wù)要求就是這樣的簡(jiǎn)單,根據(jù)不同的角色決定它能訪問(wèn)哪些頁(yè)面和哪些對(duì)象的哪些方法.目前暫時(shí)不考慮具體角色的具體權(quán)限指派,關(guān)于這部分內(nèi)容大家可以通過(guò)研究demo獲得相應(yīng)的知識(shí)。因?yàn)槭桥e例說(shuō)明Acegi的用法,現(xiàn)假設(shè)我們的web工程名為myacegi,其目錄結(jié)構(gòu)如下:
其中的secure目錄下的文件就是我們希望受控制的頁(yè)面.
src目錄是我們的java源程序。
acegilogin.jsp是我們的登錄界面.
logoff.jsp是我們的登出頁(yè)面。
test.jsp頁(yè)面中有我們對(duì)受控業(yè)務(wù)對(duì)象的受控方法的訪問(wèn)舉例。
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)用的配置了。我們?cè)谶@里先詳細(xì)說(shuō)明一下web.xml文件,其它的配置文件的內(nèi)容將在后面的改造過(guò)程中不斷深入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>
在上面的配置中,我只說(shuō)明與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è)過(guò)濾器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的請(qǐng)求訪問(wèn)都會(huì)被這個(gè)過(guò)濾器捕獲,也就是說(shuō),Acegi的頁(yè)面控制其實(shí)和我們平時(shí)的開發(fā)一樣,也是通過(guò)過(guò)濾器來(lái)實(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è)是用來(lái)動(dòng)態(tài)加載我們前面定義的應(yīng)用程序域的變量contextConfigLocation中所列出的配置文件的,第二個(gè)是Acegi內(nèi)部需求使用的事件發(fā)布器,我們不需求太多關(guān)心它的實(shí)現(xiàn)和用法,就這樣放著吧.
總的來(lái)說(shuō),這個(gè)工程本身也是以demo程序作為樣板來(lái)建立的。
想了解更多信息,建議下載范例代碼。
改造schema通過(guò)Acegi的demo演示大家可以看到,它所提供的缺省用戶驗(yàn)證辦法是依據(jù)的用戶名和登錄密碼,而對(duì)于授權(quán)訪問(wèn)方面是根據(jù)用戶所付于的角色來(lái)進(jìn)行判斷的。但在我們的業(yè)務(wù)系統(tǒng)中,用戶驗(yàn)證則有所不同。單位號(hào)、用戶ID和登錄密碼三者放在一起才能驗(yàn)證一個(gè)用戶。同樣對(duì)于用戶角色的查詢辦法也得變成以單位號(hào)加用戶ID為條件。我們先來(lái)看看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,
CONSTRAINTu(píng)nique_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語(yǔ)句來(lái)源于Acegi網(wǎng)站,應(yīng)用于hsql。網(wǎng)頁(yè)地址:
通過(guò)上面的schema可以看出Acegi是如何管理用戶和進(jìn)行授權(quán)的。也就是說(shuō),如果要讓其滿足我們前面所提出的業(yè)務(wù)要求,第一步從schema這塊就得進(jìn)行改造。
我們業(yè)務(wù)上的實(shí)際要求很簡(jiǎn)單,還沒(méi)有涉及到對(duì)象的方法訪問(wèn)的權(quán)限問(wèn)題,只是想根據(jù)用戶的角色來(lái)控制其頁(yè)面和業(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語(yǔ)法為odbc格式。
到此,schema的改造完成,趕快到我們的數(shù)據(jù)庫(kù)中實(shí)施它們吧。
改造登錄頁(yè)面我們要求,如果客戶訪問(wèn)了我們聲明要控制的頁(yè)面,則將請(qǐng)求定位到登錄頁(yè)面,要求客戶通過(guò)登錄操作向系統(tǒng)表明自己的身份。下面就是我們?cè)谙到y(tǒng)中使用的登錄界面,它合demo自帶的那個(gè)只有一點(diǎn)點(diǎn)區(qū)別,demo自帶的那個(gè)只有用戶名和登錄密碼兩個(gè)字段,而我們的是單位號(hào)、用戶ID和登錄密碼三個(gè)字段。頁(yè)面最重要的源碼如下:
<formaction=”<c:urlvalue=’j_acegi_security_check’/>"method="POST"〉
<table>
〈tr><td〉單位號(hào):〈/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è)頁(yè)面其實(shí)沒(méi)有什么特別之處,只是根據(jù)我們的業(yè)務(wù)要求修改表單的定義罷了。有一點(diǎn)要注意的是Action的值是j_acegi_security_check,這個(gè)值我們將在applicat(yī)ionContext-acegi—security.xml給出定義之所在,也就是說(shuō)這里只是引用罷了。另外還有一點(diǎn)要注意的就是其中的三個(gè)字段值:j_dwh、j_userid、j_password在后面的Acegi的代碼改造中要用到的
applicationContext—acegi—security。xml配置說(shuō)明及其實(shí)現(xiàn)先看看整體內(nèi)容:〈beans>
<?。?======================FILTERCHAIN=======================--〉
<beanid="filterChainProxy"
class="net.sf。acegisecurity。util。FilterChainProxy”〉
〈propertyname=”filterInvocationDefinitionSource">
〈value>
CONVERT_URL_TO_LOWERCASE_(tái)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_(tái)ANONYMOUS,ROLE_SUPERVISOR
/acegilogin。jsp*=ROLE_(tái)ANONYMOUS,ROLE_SUPERVISOR
/**=ROLE_SUPERVISOR
</value>
〈/property>
</bean>
〈/beans>1.
FILTERCHAIN定義了beanfilterChainProxy,需求說(shuō)明的部分是屬性filterInvocat(yī)ionDefinitionSource的值/**=httpSessionContextIntegrat(yī)ionFilter,authenticat(yī)ionProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter它表時(shí)我們的過(guò)濾器將引用的一系列Acegi服務(wù)。2。
AUTHENTICATION定義了:a)
authenticationManager,也就是認(rèn)證管理器,這個(gè)在介紹部分有說(shuō)明。它的providers屬性我們?cè)谶@里指定了兩個(gè):
i.
一個(gè)是用于數(shù)據(jù)庫(kù)認(rèn)證的daoAuthenticationProviderbean
ii。
一個(gè)是用于匿名訪問(wèn)的anonymousAuthenticationProvider
b)
userDAO,這個(gè)bean是我們自己所改造的,實(shí)現(xiàn)了我們前面說(shuō)定義的schema中users表和authorities表的訪問(wèn).在demo中,這個(gè)對(duì)象叫做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中是以u(píng)sername為標(biāo)識(shí)來(lái)區(qū)別被緩存的對(duì)象的,而我們是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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二年級(jí)下冊(cè)班級(jí)親善大使計(jì)劃
- 機(jī)房設(shè)備老化管理保障措施
- 部編版六年級(jí)上冊(cè)學(xué)生行為規(guī)范與法治教育計(jì)劃
- 2025年幼兒園設(shè)施維修保障計(jì)劃
- 高三數(shù)學(xué)組學(xué)期教學(xué)改革實(shí)施計(jì)劃
- 教科版六年級(jí)科學(xué)下冊(cè)復(fù)習(xí)測(cè)驗(yàn)計(jì)劃
- 二年級(jí)上冊(cè)食品安全教育計(jì)劃
- 小學(xué)英語(yǔ)教師信息化教學(xué)整合計(jì)劃
- 裝配工崗位職責(zé)及供應(yīng)鏈協(xié)作要求
- 復(fù)讀生創(chuàng)新創(chuàng)業(yè)指導(dǎo)計(jì)劃
- 17025檢測(cè)和校準(zhǔn)實(shí)驗(yàn)室認(rèn)可準(zhǔn)則解析
- DigestiveSystem消化系統(tǒng)英文值得收藏課件
- 外研社小學(xué)新標(biāo)準(zhǔn)英語(yǔ)單詞表匯總打印版(一年級(jí)起點(diǎn))
- 潛水泵操作JSA分析表
- 門診藥房藥物咨詢記錄表
- 質(zhì)量保證體系架構(gòu)圖
- 高中物理選修 分子動(dòng)理論
- 管道施工主要質(zhì)量保證措施及通病防治措施
- 信捷XC系列可編程序控制器用戶手冊(cè)(軟件篇)
- 新版FMEA培訓(xùn)課件
- 中考首字母填空練習(xí)67篇含答案
評(píng)論
0/150
提交評(píng)論