董一璠,李寶林,何先波
(西華師范大學(xué) 計(jì)算機(jī)學(xué)院,四川 南充 637000)
聯(lián)通資源管理系統(tǒng)是由四川南充聯(lián)通公司授權(quán),由我處完成的一個(gè)對(duì)聯(lián)通本地資源的管理系統(tǒng)。管理的資源包括各類通信設(shè)備、機(jī)房或節(jié)點(diǎn)、桿線資源、管孔資源及客戶信息等。本軟件主要用于完成聯(lián)通南充公司的各類資源的錄入、瀏覽、查詢、統(tǒng)計(jì)等功能,擬采用文字表格、邏輯圖及GIS等多種方式實(shí)現(xiàn)對(duì)各類資源的操作和管理。開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)由于各個(gè)不同部門之間需要管理的業(yè)務(wù)模塊不盡相同,互相之間既需要連通性,有需要隔離性。所以對(duì)于聯(lián)通資源管理系統(tǒng)的權(quán)限授予和權(quán)限驗(yàn)證提出了極大地要求。本系統(tǒng)采用面向?qū)ο蟮腏2EE進(jìn)行開(kāi)發(fā),系統(tǒng)是典型的B/S結(jié)構(gòu)。所以我們采用Spring Security安全框架對(duì)整個(gè)系統(tǒng)的安全框架進(jìn)行搭建,采用嚴(yán)格的權(quán)限控制和角色化的操作界面實(shí)現(xiàn)整個(gè)系統(tǒng)的安全性和操作界面的簡(jiǎn)潔性。既很好的解決了系統(tǒng)權(quán)限控制問(wèn)題,而且安全可靠,便于移植重利用。
在基于B/S結(jié)構(gòu)的J2EE企業(yè)級(jí)應(yīng)用系統(tǒng)中,客戶登陸認(rèn)證、訪問(wèn)授權(quán)控制是重要組成部分,Spring Security提供了一個(gè)較成熟的安全框架[1]。
Spring Security是由Acegi Security發(fā)展而來(lái)的,是Spring框架的組成部分,Spring Security框架主要提供“認(rèn)證”和“授權(quán)訪問(wèn)”,“認(rèn)證”為用戶建立一個(gè)他所需要聲明的主題,即用戶或在你系統(tǒng)中執(zhí)行的其他設(shè)備或系統(tǒng)。另一個(gè)是“授權(quán)”,授權(quán)是指已經(jīng)提前建立好了某個(gè)用戶被授予的權(quán)利,能否執(zhí)行某個(gè)操作,在執(zhí)行之前就已經(jīng)進(jìn)行了授權(quán)判斷。Spring Security也支持大量的第三方驗(yàn)證模型[2]。
Spring Security通過(guò)使用Servlet過(guò)濾器對(duì)Web安全性進(jìn)行支持,過(guò)濾器過(guò)濾Servlet的訪問(wèn)請(qǐng)求,將這些請(qǐng)求轉(zhuǎn)發(fā)給認(rèn)證授權(quán)管理決策處理器進(jìn)行安全處理,從而曾強(qiáng)了系統(tǒng)的訪問(wèn)安全性。每一個(gè)請(qǐng)求發(fā)出后,至少要經(jīng)過(guò)以下4個(gè)過(guò)濾器,如圖1所示。
圖1 四重安全過(guò)濾器結(jié)構(gòu)Fig.1 Four security filters structure
1)集成過(guò)濾器:負(fù)責(zé)在請(qǐng)求剛發(fā)出的時(shí)候檢驗(yàn)是否在HTTP會(huì)話中已經(jīng)存儲(chǔ)了一個(gè)用戶的驗(yàn)證信息,為其他過(guò)濾器的處理做準(zhǔn)備。
2)認(rèn)證處理過(guò)濾器:負(fù)責(zé)判斷是否為一個(gè)認(rèn)證請(qǐng)求。如果是,相關(guān)的認(rèn)證信息會(huì)從中提取出來(lái),然后轉(zhuǎn)移給認(rèn)證管理器進(jìn)行處理,確定這個(gè)用戶的身份。如果不是,認(rèn)證處理過(guò)濾器不做任何處理,該請(qǐng)求繼續(xù)前進(jìn)。
3)例外轉(zhuǎn)換過(guò)濾器:負(fù)責(zé)將可能被拋出的異常“Access Denied Exception”和 “Authentication Exception”轉(zhuǎn)化為對(duì)應(yīng)的HTTP響應(yīng)。
4)過(guò)濾器安全攔截器:負(fù)責(zé)Web應(yīng)用程序的安全攔截。檢查請(qǐng)求中的用戶是否是具有訪問(wèn)被保護(hù)資源的的權(quán)限的用戶。它的工作依賴于認(rèn)證管理器和訪問(wèn)決策管理器[3]。
為了使用Spring Security框架,在WEB項(xiàng)目的web.xml中需作如下配置:
其中springSecurityFilterChain過(guò)濾器是Spring Security框架的總體配置,applicationContext*.xml是對(duì)所有Spring配置文件導(dǎo)入的配置。Spring Security的配置文件名為applicationcontext-security.xml。
在聯(lián)通資源管理系統(tǒng)中,因?yàn)橛脩袅看?,所以用戶需要用?shù)據(jù)庫(kù)中的表進(jìn)行保存。表中的用戶和密碼信息的查詢信息通過(guò)UserService實(shí)現(xiàn)。我們的系統(tǒng)中UserService實(shí)現(xiàn)用戶認(rèn)證(authentiation)和資源訪問(wèn)授權(quán)(Authorization)的相關(guān)基本操作,其中包括用戶和密碼的添加、刪除、更改和查詢。在實(shí)現(xiàn)中,UserService需實(shí)現(xiàn)UserDetailsService接口,該接口也是spring認(rèn)證框架要求實(shí)現(xiàn)的。UserDetailsService接口只包 含 一 個(gè) 方 法 :UserDetails loadUserByUsername (String username)。該方法通過(guò)用戶名去查詢用戶相關(guān)的詳細(xì)信息,返回實(shí)現(xiàn)UserDetails接口的類,對(duì)框架來(lái)說(shuō),其操作主要通過(guò)UserDetailsService和UserDetails實(shí)現(xiàn)。在我們的項(xiàng)目中使用類UserDetailsImpl類實(shí)現(xiàn)接口UserDetails, 如下是
在UserDetailsImpl中定義了一個(gè)很重要的Java Bean——uservo。在我們的項(xiàng)目中,User為PO對(duì)象,與數(shù)據(jù)庫(kù)中的表user的記錄對(duì)應(yīng)。UserVO為VO對(duì)象,根據(jù)業(yè)務(wù)邏輯進(jìn)行加工:
在UserService實(shí)現(xiàn)類中,通過(guò)public void init(){umapper=session.getMapper(UserMapper.class); } 實(shí)現(xiàn)與數(shù)據(jù)庫(kù)表及基本操作的關(guān)聯(lián),UserMapper為CRUD操作實(shí)現(xiàn)接口,框架會(huì)自動(dòng)實(shí)現(xiàn)相關(guān)類的實(shí)例化 (UserMapper.xml在mybatis配置文件中引用,UserExample與User類會(huì)在UserMapper接口框架實(shí)現(xiàn)中引用,框架可采用動(dòng)態(tài)代理等技術(shù)得到類實(shí)例).UserVO除了包括User的信息以外,還須對(duì)User信息進(jìn)一步細(xì)化,如GroupId到Group類實(shí)例,另外,授權(quán)部分,我們的系統(tǒng)并未在庫(kù)中實(shí)現(xiàn),而是嵌在代碼中,故需找到該部分內(nèi)容。這些主要在如下調(diào)用中實(shí)現(xiàn)(由convert2vo完 成 ):UserDetails ud= new UserDetailsImpl (convert2vo(user));由此可知,認(rèn)證的基本思想及調(diào)用實(shí)現(xiàn)如下:
1)org.springframework.security.core.context.SecurityContext接口表示的是當(dāng)前應(yīng)用的安全上下文。通過(guò)此接口可以獲取和設(shè)置當(dāng)前的認(rèn)證對(duì)象。org.springframework.security.core.Authentication接口用來(lái)表示此認(rèn)證對(duì)象。通過(guò)認(rèn)證對(duì)象的方法可以判斷當(dāng)前用戶是否已經(jīng)通過(guò)認(rèn)證,以及獲取當(dāng)前認(rèn)證用戶的相關(guān)信息,包括用戶名、密碼和權(quán)限等。
2)要使用此認(rèn)證對(duì)象,首先需要獲取到 Security Context對(duì)象。通過(guò) org.springframework.security.core.context.Security Context Holder類提供的靜態(tài)方法 getContext()就可以獲取。
3)通過(guò) SecurityContext對(duì)象的 getAuthentication()方法可以得到認(rèn)證對(duì)象。通過(guò)認(rèn)證對(duì)象的 getPrincipal()方法就可以獲得當(dāng)前的認(rèn)證主體,通常是UserDetails接口的實(shí)現(xiàn)。
4)典型的認(rèn)證過(guò)程就是當(dāng)用戶輸入了用戶名和密碼之后,UserDetailsService通過(guò)用戶名找到對(duì)應(yīng)的UserDetails對(duì)象,接著比較密碼是否匹配。如果不匹配,則返回出錯(cuò)信息;如果匹配的話,說(shuō)明用戶認(rèn)證成功,就創(chuàng)建一個(gè)實(shí)現(xiàn)了Authentication接口的對(duì)象,如 org.springframework.security.authentication.Username Password AuthenticationToken類的對(duì)象。再通過(guò)SecurityContext的setAuthentication()方法來(lái)設(shè)置此認(rèn)證對(duì)象。
綜上所述,整個(gè)登錄過(guò)程如圖2所示。
圖2 登陸安全驗(yàn)證結(jié)構(gòu)Fig.2 Login Security verification structure
系統(tǒng)要首先根據(jù)需要定義好角色,并為每一角色分配合適的訪問(wèn)權(quán)限,然后再根據(jù)用戶的職責(zé)和權(quán)利指派不同的角色。這樣就實(shí)現(xiàn)了權(quán)限和用戶的邏輯分離,使得權(quán)限分配的靈活性問(wèn)題得以解決。在聯(lián)通資源管理系統(tǒng)中,我們也是按照聯(lián)通公司對(duì)企業(yè)人員的分組對(duì)角色進(jìn)行分配的,對(duì)于每個(gè)模塊都要有相應(yīng)的讀(R)寫(W)查(S)權(quán)限的管理。不同分組用戶對(duì)不同模塊具有不同的權(quán)限,需要分別授予,如圖3所示。
圖3 權(quán)限控制結(jié)構(gòu)Fig.3 Authority manage structure
系統(tǒng)的角色通過(guò)枚舉RoleEnum實(shí)現(xiàn),這也是用戶管理權(quán)限設(shè)置部分的信息來(lái)源:
授權(quán)是以組的方式存在,故一個(gè)Authority有組標(biāo)識(shí),其權(quán)限由其分配的角色而定,一個(gè)組可能對(duì)應(yīng)多個(gè)Authority。
系統(tǒng)用戶的權(quán)限獲取在UserService.getAuthorities方法中實(shí)現(xiàn),根據(jù)枚舉內(nèi)容賦予所有權(quán)限(讀、寫和執(zhí)行),代碼如下:
一般用戶的權(quán)限則通過(guò)組 AuthorityService.getAuthoritiesByGroupId方法實(shí)現(xiàn),在authority表中內(nèi)容如圖4所示。
圖4 用戶組權(quán)限表Fig.4 User group permissions list
在spring安全機(jī)制中,有大量的如下配置:
特別是在applicationContext-security.xml中。這是在配置文件中集中配置允許登入的權(quán)限。該方式主要針對(duì)URL地址及參數(shù)過(guò)濾,主要用于控制網(wǎng)頁(yè)整體的訪問(wèn),可在實(shí)現(xiàn)中對(duì)各網(wǎng)頁(yè)名字和存儲(chǔ)路徑進(jìn)行合理規(guī)劃達(dá)到安全控制的目的。另外,也可通過(guò)struts配置實(shí)現(xiàn)對(duì)方法訪問(wèn)的控制,但struts配置較龐大。還有一種方式,是通過(guò)jsp的安全按標(biāo)簽實(shí)現(xiàn)對(duì)網(wǎng)頁(yè)元素的顯示控制,例如
authorize標(biāo)簽用來(lái)決定它的內(nèi)容是否會(huì)被執(zhí)行,另外,<sec:authentication?標(biāo)簽用于訪問(wèn)當(dāng)前的Authentication對(duì)象,保存在安全上下文中。
通過(guò)UserDetails接口中的getAuthorities()方法實(shí)現(xiàn)的,該方法返回一權(quán)限名字字符串集合。本系統(tǒng)的具體實(shí)現(xiàn)如下:
上面代碼中,GrantedAuthorityImpl包含了字符串名(role字符串成員變量),并實(shí)現(xiàn)了GrantedAuthority接口。綜上可知,UserService實(shí)現(xiàn)了框架所需的所有操作,UserVO包含了安全相關(guān)的所有信息,UserDetailsImpl實(shí)現(xiàn)了框架所需要的接口。
在基于J2EE的企業(yè)級(jí)B/S項(xiàng)目中,安全是一個(gè)自發(fā)展開(kāi)始以來(lái)一直非常受到重視的內(nèi)容。在系統(tǒng)的開(kāi)發(fā)過(guò)程中,對(duì)于代碼的復(fù)用率,可移植性等問(wèn)題,一直是程序開(kāi)發(fā)人員的頭等大事。而Spring Security為我們提供了一個(gè)十分便利有效的管理模塊。通過(guò)對(duì)端口的加載,和對(duì)攔截器與權(quán)限的配置,可以讓你的系統(tǒng)在很短的時(shí)間內(nèi),就擁有一個(gè)良好的安全機(jī)制。在使用過(guò)程中發(fā)現(xiàn)的問(wèn)題如下:
1)由于采用將用戶信息保存在session中,當(dāng)修改或更新了用戶信息后,無(wú)法立刻將新的用戶信息用于當(dāng)前用戶。實(shí)時(shí)更新用戶信息,是目前Spring Security的一個(gè)大問(wèn)題[4]。
2)應(yīng)該考慮如何引入spring AOP對(duì)方法進(jìn)行控制。
[1]蒲子明,許勇,王黎.Struct+Hibernate+Spring整合開(kāi)發(fā)技術(shù)詳解[M].北京:清華大學(xué)出版社,2010.
[2]佚名.Spring安全框架 [EB/OL].[2012-11-18]http://www.oschina.net/p/spring+security.
[3]佚名.Spring Security介紹 (4)[EB/OL].[2012-11-18]http://www.4ucode.com/study/topic/353380.
[4]馬楠.基于Spring的J2EE安全框架的研究與應(yīng)用[D].北京:北京郵電大學(xué),2009.
[5]丁振凡.基于Spring Security的Web資源訪問(wèn)控制[J].宜春學(xué)院學(xué)報(bào),2012(8):36-1250.DING Zhen-fan.Access control for web resources based on spring security[J].Journal of Yichun University,2012(8):36-1250.
[6]熊昊.基于Spring的Acegi安全框架及其應(yīng)用研究[D].長(zhǎng)沙:國(guó)防科學(xué)技術(shù)大學(xué),2008.