摘 要 spring框架是一個優(yōu)秀的多層j2ee系統(tǒng)框架,spring本身沒有提供對系統(tǒng)的安全性支持。acegi是基于spring ioc 和 aop機制實現(xiàn)的一個安全框架。本文探討了acegi安全框架中各部件之間的交互,并通過擴展acegi數(shù)據(jù)庫設(shè)計來實現(xiàn)基于spring框架的應(yīng)用的安全控制方法。
關(guān)鍵詞 spring ;acegi ;認(rèn)證; 授權(quán)
引言
近年來,隨著internet技術(shù)的迅猛發(fā)展,計算機網(wǎng)絡(luò)已深入到了人們的工作、學(xué)習(xí)和日常生活中,于是,怎樣構(gòu)建安全的web應(yīng)用也成為了當(dāng)前最熱門的話題。spring是一個基于ioc(inversion of control)和aop(aspect oriented programming)的構(gòu)架多層j2ee應(yīng)用系統(tǒng)的框架。spring框架正在以其優(yōu)良的特性吸引了越來越多的開發(fā)人員的關(guān)注,并在大量的系統(tǒng)開發(fā)中被使用。然而,現(xiàn)有的spring框架本身并沒有提供對系統(tǒng)安全性的支持,本文通過介紹一種可用于spring框架中的安全框架acegi,并對在spring框架中使用acegi實現(xiàn)安全用戶認(rèn)證和資源授權(quán)控制進(jìn)行了較深入的研究和擴展,同時給出了可行的解決方案。
spring框架和acegi安全框架介紹
1、spring 框架
spring框架是由open source開發(fā)的一個優(yōu)秀的多層j2ee系統(tǒng)框架,它為企業(yè)級應(yīng)用提供了一個非常輕量級的解決方案,大大地降低了應(yīng)用開發(fā)的難度與復(fù)雜度,提高了開發(fā)的速度。
spring框架的核心是ioc和aop。ioc是一種設(shè)計模式,即ioc模式。ioc模式進(jìn)一步降低了類之間的耦合度,并且改變了傳統(tǒng)的對象的創(chuàng)建方法,實現(xiàn)了一種配置式的對象管理方式,spring框架中由ioc容器負(fù)責(zé)配置性的對象的管理。ioc模式極大的提高了系統(tǒng)開發(fā)與維護(hù)的靈活性。
aop是一種編程模式,它是從系統(tǒng)的橫切面關(guān)注問題。傳統(tǒng)的面向?qū)ο缶幊蘯op主要從系統(tǒng)的垂直切面對問題進(jìn)行關(guān)注,對于系統(tǒng)的橫切面關(guān)注很少,或者說很難關(guān)注,這樣當(dāng)考慮到系統(tǒng)的安全性、日志、事務(wù)以及其他企業(yè)級服務(wù)時,oop就無能為力了,只能在所有相關(guān)類中加入類似的系統(tǒng)服務(wù)級的代碼。aop為解決系統(tǒng)級服務(wù)問題提供了一種很好的方法。aop將系統(tǒng)服務(wù)分解成方面看待,并為類提供一種聲明式系統(tǒng)服務(wù)方式。java類不需要知道日志服務(wù)的存在也不需要考慮相關(guān)的代碼。所以,用aop編寫的應(yīng)用程序是松耦合的,代碼的復(fù)用性就提高了。
2、acegi 安全框架
借助于spring框架,開發(fā)者能夠快速構(gòu)建結(jié)構(gòu)良好的web應(yīng)用,但現(xiàn)有的spring框架本身沒有提供安全相關(guān)的解決方案。同樣來自于open source 社區(qū)的acegi安全框架為實現(xiàn)基于spring框架的web應(yīng)用的安全控制提供了一個很好的解決方案。acegi本身就是利用spring提供的ioc和aop機制實現(xiàn)的一個安全框架,它將安全性服務(wù)作為j2ee平臺中的系統(tǒng)級服務(wù),以aop aspect形式發(fā)布。所以借助于acegi安全框架,開發(fā)者能夠在spring使能應(yīng)用中采用聲明式方式實現(xiàn)安全控制。
acegi安全框架主要由安全管理對象、攔截器以及安全控制管理組件組成。安全管理對象是系統(tǒng)可以進(jìn)行安全控制的實體,acegi框架主要支持方法和url請求兩類安全管理對象;攔截器是acegi中的重要部件,用來實現(xiàn)安全控制請求的攔截,針對不同的安全管理對象的安全控制請求使用不同的攔截器進(jìn)行攔截;安全控制管理部件是實際實現(xiàn)各種安全控制的組件,對被攔截器攔截的請求進(jìn)行安全管理與控制,主要組件包括實現(xiàn)用戶身份認(rèn)證的authenticationmanager、實現(xiàn)用戶授權(quán)的accessdecisionmanager 以及實現(xiàn)角色轉(zhuǎn)換的runasmanager。安全管理對象、攔截器以及安全控制管理組件三者關(guān)系如圖1所示。
acegi安全框架在基于spring框架的系統(tǒng)中的應(yīng)用
1、分析系統(tǒng)安全性需求
首先,需要明確進(jìn)行安全控制的對象,可為業(yè)務(wù)方法和url資源。
其次,需要進(jìn)一步明確,系統(tǒng)身份認(rèn)證資料和資源授權(quán)信息的數(shù)據(jù)持久化形式。
2、acegi安全系統(tǒng)數(shù)據(jù)庫設(shè)計
在acegi框架中支持多種安全信息的持久化方式,可以在配置文件中配置或存放在關(guān)系數(shù)據(jù)庫。由于在實際應(yīng)用中,需求是經(jīng)常發(fā)生變化的。所以,在配置文件中配置是滿足不了實際應(yīng)用需求的。然而,acegi本身對權(quán)限表的設(shè)計非常簡單,users表{username,password,enabled} 和authorities表{username,authority},這樣簡單的設(shè)計肯定無法適用復(fù)雜的權(quán)限需求。為了解決權(quán)限管理的復(fù)雜性,在這里引入了role(角色)的概念,使得用戶和權(quán)限分離,一個用戶擁有多個角色,一個角色擁有多個相應(yīng)的權(quán)限,這樣就更靈活地支持安全策略。
同時,為了更好地配合acegi安全框架,還引入resource(資源)的概念,資源可分為url和function(方法)兩種,一個權(quán)限可以對應(yīng)多個資源。具體的數(shù)據(jù)庫設(shè)計見圖2。

圖1 安全管理對象,攔截器和安全管理組件交互圖

圖2 acegi安全控制系統(tǒng)數(shù)據(jù)庫設(shè)計
3、認(rèn)證管理器,授權(quán)管理器的配置
實現(xiàn)系統(tǒng)的安全控制,首先需要對系統(tǒng)的安全管理器和授權(quán)管理器進(jìn)行配置,系統(tǒng)進(jìn)行認(rèn)證和授權(quán)需要獲取安全信息,acegi本身提供了對認(rèn)證信息的獲取機制,在實現(xiàn)認(rèn)證與授權(quán)過程中,系統(tǒng)將主動根據(jù)配制信息和相應(yīng)的信息解釋安全信息的讀取。圖3給出了一個將用戶安全信息存儲在數(shù)據(jù)庫中的認(rèn)證管理器的配置示意圖。
對應(yīng)于圖示的xml配置文件的代碼如下:
/* 配置數(shù)據(jù)庫datasource 和acegi 的 jdbcdao */
<bean id=”datasource” class=”org.springframework.jdbc.datasource.drivermanagerdatasource”>
<property name=”driverclassname”>
?。紇alue>${jdbc.driverclassname}</value>
?。?property>
?。紁roperty name=”url”>
<value>${jdbc.url}</value>
</property>

圖3 認(rèn)證管理器配制示意圖
<property name=”username”>
<value>${jdbc.username}</value>
</property>
<property name=”password”>
<value>${jdbc.password}</value>
</property>
</bean>
<bean id=”jdbcdaoimpl” class=”org.acegisecurity. roviders. dao.jdbc.jdbcdaoimpl”>
?。紁roperty name=”datasource”>
<ref bean=”datasource”/>
?。?property>
</bean>
/*配置用戶信息的加密算法*/
<bean id=”passwordencoder”
class=”org.acegisecurity.providers.encoding.md5passwordencoder”/>
/*配置緩存有效時間*/
<bean id=”usercache” class=”org.acegisecurity. providers. dao.cache.ehcachebasedusercache”>
…//這里對緩存有效時間進(jìn)行設(shè)置
</bean>
/*配置daoauthenticationprovider*/
<bean id=”daoauthenticationprovider”
class=”org.acegisecurity.providers.dao.daoauthenticationprovider”>
<property name=”authenticationdao”>
?。紃ef local=”jdbcdaoimpl”/>
?。?property>
<property name=”passwordencoder”>
?。紃ef local=” passwordencoder”/>
?。?property>
<property name=”usercache”>
?。紃ef local=” usercache”/>
?。?property>
</bean>
/*配置認(rèn)證管理器*/
<bean id=”authenticationmanager” class=”org.acegisecurity. providers.providermanager”>
?。紁roperty name=”providers”>
<list>
<ref local=”daoauthenticationprovider”/>
?。?list>
?。?property>
</bean>
授權(quán)管理器的配置方法與認(rèn)證管理器的配置基本類似,這里不再討論。
4、安全請求攔截器的配置
以上配置完成后,就需要配置安全攔截器。不同的安全管理對象需要使用不同的安全攔截器。對于方法級的安全認(rèn)證需要使用的攔截器為methodsecurityinterceptor,而應(yīng)用于url資源的安全攔截器為filtersecurityinterceptor 。其中,methodsecurityinterceptor攔截器是借助于spring aop實現(xiàn)的,而filtersecurityinterceptor攔截器是借助于servlet filter 實現(xiàn)的。本文以url資源請求的安全攔截器為例說明配置情況。
由于url資源請求安全攔截是借助于過濾器進(jìn)行的。因此首先要配置acegi servlet過濾器。過濾器類似于aop around裝備,實現(xiàn)在web資源調(diào)用前后進(jìn)行的一些操作6種過濾器,他們依次構(gòu)成servlet過濾器鏈,依次處理客戶請求。需要注意的是過濾器配置的順序是不能交換的,當(dāng)不需要使用某個過濾器時,可直接將其刪除和注釋。過濾器在web.xml中配置形式為
<filter>
?。糵ilter-name>acegi http request security filter</filter-name>
<filter-class>org.acegisecurity.util.filtertobeanproxy</filter-class>
?。糹nit-param>
?。紁aram-name>targetclass</param-name>
?。紁aram-value>
org.acegisecurity.intercept.web.securityenforcementfilter
?。?param-value>
?。?init-param>
</filter>
<filter-mapping>
<filter-name>acigi http request security filter</filter-name>
?。紆rl-pattern>/*</url-pattern>
</filter-mapping>
在spring applicationcontext.xml文件中的配置形式為
<bean id=”securityenforcementfilter” class=””>
<property name=”filtersecurityinterceptor”>
?。紃ef bean=”filterinvocationinteceptor”/>
?。?property>
<property name=”authenticationentrypoint”>
?。紃ef bean=”authenticationprocessingfilterentrypoint”/>
?。?property>
以上代碼是securityenforcementfilter的配置,該過濾器對用戶是否有權(quán)訪問web資源作出最后的決定。其它的過濾器的配置類同。
配置完過濾器后,需要對攔截器filtersecurityinterceptor進(jìn)行配置,
<bean id=”filterinvocationinterceptor”
class=””>
?。紁roperty name=”authenusercacheticationmanager”>1
<property name=”accessdecisionmanager”>
?。紁roperty name=”objectdefinitionsource”>
<ref local="filterobjectdefinitionsource"/>
?。?property>
<bean id="filterobjectdefinitionsource"
class="org.xiaohongli.acegi.db.dbfilterobjectdefinitionsource">
<constructor-arg><refbean="jdbctemplate"/>
?。?constructor-arg>
</bean>
objectdefinitionsource屬性定義了那些受保護(hù)的url資源,其中引用了一個本地對象filterobjectdefinitionsource。filterobjectdefinitionsource類從數(shù)據(jù)庫中讀取需要保護(hù)的url安全信息,它擴展了pathbasedfilterinvocationdefinition map類。
同樣,實現(xiàn)了另外一個methodobjectdefinitionsource類從數(shù)據(jù)庫中讀取需要保護(hù)的function資源,它擴展了methoddefinitionmap類。限于篇幅,在這里就不列出具體實現(xiàn)的源代碼。
<bean id="methodobjectdefinitionsource"
class="org.xiaohongli.acegi.db.dbmethodobjectdefinitionsource">
<constructor-arg><refbean="jdbctemplate"/>
</constructor-arg>
</bean>
結(jié)束語
由于spring在越來越多的項目中的應(yīng)用,因此基于spring應(yīng)用的安全控制系統(tǒng)的研究就顯得非常重要。acegi提供了對spring應(yīng)用安全的支持,然而 acegi本身提供的實例并不能滿足大規(guī)模的復(fù)雜的權(quán)限需求,本文通過擴展acegi的數(shù)據(jù)庫設(shè)計即可滿足復(fù)雜的權(quán)限需求。然而,怎樣將acegi應(yīng)用到非spring的系統(tǒng)中,還有待進(jìn)一步研究。