轉自:http://www.cublog.cn/u/11905/showart_162625.html
最近在做項目遇到了權限管理,用戶要求可以自己建立不同的角色對系統的資源進行控制, 不同的用戶有不同的角色,又恰恰框架中用到了struts+spring+hibernate,要求在web層調用 業務邏輯層 時不考慮權限,web層可以控制用戶的顯示界面,邏輯層處理用戶權限問題。
想來想去好像只有spring 的aop 可以做到,在調用到 接口 中的方法時,首先檢查用戶的權限,如果檢查通過則繼續執行,否則拋出異常。但是新的問題又出現了,如何在邏輯層上來得到當前用戶的id,以致用戶的 角色,總不能每次都要從web中傳來一個 httprequest,或者 session 這類的吧。在網上看了很多資料,發現了acegi,恰好解決了以上的難題,具體的實現原理這里就不多說了,網上有很多相關資料。
說正題,首先來看看acegi 的官方 example ,我下載的是acegi-security-1.0.0-RC1,解壓縮后可以看到acegi-security-sample-contacts-filter.war,打開配置文件有這樣幾句
?1???<bean?id="contactManagerSecurity"?class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">?
?2???????<property?name="authenticationManager"><ref?bean="authenticationManager"/></property>?
?3???????<property?name="accessDecisionManager"><ref?local="businessAccessDecisionManager"/></property>?
?4???????<property?name="afterInvocationManager"><ref?local="afterInvocationManager"/></property>?
?5???????<property?name="objectDefinitionSource">?
?6??????????<value>?
?7?????????????sample.contact.ContactManager.create=ROLE_USER?
?8?????????????sample.contact.ContactManager.getAllRecipients=ROLE_USER?
?9?????????????sample.contact.ContactManager.getAll=ROLE_USER,AFTER_ACL_COLLECTION_READ?
10?????????????sample.contact.ContactManager.getById=ROLE_USER,AFTER_ACL_READ?
11?????????????sample.contact.ContactManager.delete=ACL_CONTACT_DELETE?
12?????????????sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN?
13?????????????sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN?
14??????????</value>?
15???????</property>?
16????</bean>?
17?
可以看到它是通過讀配置文件來判斷執行某個方法所需要的角色的,再看這幾句
<bean?id="filterInvocationInterceptor"?class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">?
??????<property?name="authenticationManager"><ref?bean="authenticationManager"/></property>?
??????<property?name="accessDecisionManager"><ref?local="httpRequestAccessDecisionManager"/></property>?
??????<property?name="objectDefinitionSource">?
?????????<value>?
????????????????????????????CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON?
????????????????????????????PATTERN_TYPE_APACHE_ANT?
????????????????????????????/index.jsp=ROLE_ANONYMOUS,ROLE_USER?
????????????????????????????/hello.htm=ROLE_ANONYMOUS,ROLE_USER?
????????????????????????????/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER?
????????????????????????????/switchuser.jsp=ROLE_SUPERVISOR?
????????????????????????????/j_acegi_switch_user=ROLE_SUPERVISOR?
????????????????????????????/acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER?
????????????????????????????????/**=ROLE_USER?
?????????</value>?
??????</property>?
???</bean>?

同樣是將頁面的訪問權限寫死在配置文件中,再來看看它的tag是如何處理的
<auth:authorize?ifAnyGranted="ROLE_DELETE">?
??????????<a?href="">刪除</a>?
</auth:authorize>?可見它是要求我們對鏈接或者其他資源的保護時提供 用戶角色,可是既然角色是用戶自己添加的我們又如何來寫死在這里呢?
還有就是它對用戶驗證默認使用的是jdbc,即 JdbcDaoImpl
<bean?id="transactionManager"?class="org.springframework.jdbc.datasource.DataSourceTransactionManager">?
????????????????<property?name="dataSource"><ref?local="dataSource"/></property>?
????????</bean>?而我們希望基于Hibernate的Dao來實現。
可見僅僅使用現有的acegi 是 無法滿足我們項目開發的需求的。
解決方法:1: 開發基于數據庫的保護資源。
看過acegi的源代碼就會知道,對保護資源的定義是通過實現ObjectDefinitionSource這個接口來實現的,而且acegi為我們提供了默認實現的抽象類
public?abstract?class?AbstractMethodDefinitionSource?

????implements?MethodDefinitionSource?
{?
????//~?Static?fields/initializers?=============================================?

????private?static?final?Log?logger?=?LogFactory.getLog(AbstractMethodDefinitionSource.class);?

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

????public?ConfigAttributeDefinition?getAttributes(Object?object)?

????????throws?IllegalArgumentException?
{?
????????Assert.notNull(object,?"Object?cannot?be?null");?


????????if?(object?instanceof?MethodInvocation)?
{?
????????????return?this.lookupAttributes(((MethodInvocation)?object).getMethod());?
????????}?


????????if?(object?instanceof?JoinPoint)?
{?
????????????JoinPoint?jp?=?(JoinPoint)?object;?
????????????Class?targetClazz?=?jp.getTarget().getClass();?
????????????String?targetMethodName?=?jp.getStaticPart().getSignature().getName();?
????????????Class[]?types?=?((CodeSignature)?jp.getStaticPart().getSignature())?
????????????????????.getParameterTypes();?


????????????if?(logger.isDebugEnabled())?
{?
????????????????logger.debug("Target?Class:?"?+?targetClazz);?
????????????????logger.debug("Target?Method?Name:?"?+?targetMethodName);?


????????????????for?(int?i?=?0;?i?<?types.length;?i++)?
{?

????????????????????if?(logger.isDebugEnabled())?
{?
????????????????????????logger.debug("Target?Method?Arg?#"?+?i?+?":?"?
????????????????????????????????+?types[i]);?
????????????????????}?
????????????????}?
????????????}?


????????????try?
{?
????????????????return?this.lookupAttributes(targetClazz.getMethod(targetMethodName,?types));?

????????????}?catch?(NoSuchMethodException?nsme)?
{?
????????????????throw?new?IllegalArgumentException("Could?not?obtain?target?method?from?JoinPoint:?"?+?jp);?
????????????}?
????????}?

????????throw?new?IllegalArgumentException("Object?must?be?a?MethodInvocation?or?JoinPoint");?
????}?


????public?boolean?supports(Class?clazz)?
{?
????????return?(MethodInvocation.class.isAssignableFrom(clazz)?
????????||?JoinPoint.class.isAssignableFrom(clazz));?
????}?


????protected?abstract?ConfigAttributeDefinition?lookupAttributes(Method?method);?
}?

我們要做的就是實現它的
protected abstract ConfigAttributeDefinition lookupAttributes(Method method);方法,
以下是我的實現方法,大致思路是這樣,通過由抽象類傳來的Method 對象得到
調用這個方法的 包名,類名,方法名 也就是secureObjectName, 查詢數據庫并將結果映射為Function 也就是secureObject ,由于Function 與 Role 的多對多關系 可以得到 Function所對應的 Roles ,在將role 包裝成GrantedAuthority (也就是acegi中的角色)。其中由于頻繁的對數據庫的查詢 所以使用Ehcache 來作為緩存。
??1?package?sample.auth;?
??2?
??3?import?java.lang.reflect.Method;?
??4?import?java.util.ArrayList;?
??5?import?java.util.Arrays;?
??6?import?java.util.Collection;?
??7?import?java.util.Iterator;?
??8?import?java.util.List;?
??9?import?java.util.Set;?
?10?
?11?import?org.acegisecurity.ConfigAttributeDefinition;?
?12?import?org.acegisecurity.ConfigAttributeEditor;?
?13?import?org.acegisecurity.GrantedAuthority;?
?14?import?org.acegisecurity.GrantedAuthorityImpl;?
?15?import?org.acegisecurity.intercept.method.AbstractMethodDefinitionSource;?
?16?import?org.springframework.util.Assert;?
?17?
?18?import?sample.auth.cache.AuthorityBasedFunctionCache;?
?19?import?sample.auth.cache.info.FunctionByNameCache;?
?20?import?sample.dao.IBaseDao;?
?21?import?sample.mappings.function.Function;?
?22?import?sample.mappings.role.Role;?
?23?
?24?public?class?DatabaseDrivenMethodDefinitionSourcew?extends?
?25?????????????????AbstractMethodDefinitionSource?{?
?26?????????
?27?????????//?baseDao?提供通過HIbenate對數據庫操作的實現?
?28?????????private?IBaseDao?baseDao;?
?29?????????//?AuthorityBasedFunctionCache?通過Function?查?Role?時緩存?
?30?????????private?AuthorityBasedFunctionCache?cache;?
?31?????????//?FunctionByNameCache?由反射到的方法名查找?數據庫對應的Function?時的緩存?
?32?????????private?FunctionByNameCache?functionCache;?
?33?
?34?????????public?FunctionByNameCache?getFunctionCache()?{?
?35?????????????????return?functionCache;?
?36?????????}?
?37?
?38?????????public?void?setFunctionCache(FunctionByNameCache?functionCache)?{?
?39?????????????????this.functionCache?=?functionCache;?
?40?????????}?
?41?
?42?????????protected?ConfigAttributeDefinition?lookupAttributes(Method?mi)?{?
?43?????????
?44?????????????????Assert.notNull(mi,"lookupAttrubutes?in?the?DatabaseDrivenMethodDefinitionSourcew?is?null");?
?45?????????????????String?secureObjectName=mi.getDeclaringClass().getName()?+"."+?mi.getName();?
?46?????????????????//Function?為數據庫中保護資源的映射?
?47?????????????????Function?secureObject=functionCache.getFunctionByCache(secureObjectName);?
?48?
?49?????????????????if(secureObject==null)//if?secure?object?not?exist?in?database?
?50?????????????????{?
?51?????????????????????????secureObject=(Function)baseDao.loadByKey(Function.class,?"protectfunction",?secureObjectName);?
?52?????????????????????????functionCache.putFunctionInCache(secureObject);?
?53?????????????????}?
?54?????????????????????
?55?????????????????if(secureObject==null)?
?56?????????????????????????Assert.notNull(secureObject,"secureObject(Function)?not?found?in?db");?
?57?????????????????//retrieving?roles?associated?with?this?secure?object?
?58?????????????????
?59?????????????????Collection?roles?=?null;?
?60?????????????????GrantedAuthority[]?grantedAuthoritys?=?cache.getAuthorityFromCache(secureObject.getName());?
?61?????????????????//?如果是第一次?cache?為空?
?62?????????????????if(grantedAuthoritys?==?null){?
?63?????????????????????????
?64?????????????????????????Set?rolesSet?=?secureObject.getRoles();?
?65?????????????????????????Iterator?it?=?rolesSet.iterator();?
?66?????????????????????????List?list?=?new?ArrayList();?
?67?????????????????????????while(it.hasNext()){?
?68?????????????????????????????????
?69?????????????????????????????????Role?role?=?(Role)it.next();?
?70?????????????????????????????????GrantedAuthority?g?=?new??GrantedAuthorityImpl(role.getName());?
?71?????????????????????????????????list.add(g);????????
?72?????????????????????????}?
?73?????????????????????????grantedAuthoritys?=?(GrantedAuthority[])list.toArray(new?GrantedAuthority[0]);?
?74?????????????????????????cache.putAuthorityInCache(secureObject.getName(),grantedAuthoritys);?
?75?????????????????????????roles?=?Arrays.asList(grantedAuthoritys);?
?76?????????????????}else{?
?77?????????????????????????
?78?????????????????????????roles?=?Arrays.asList(grantedAuthoritys);?
?79?????????????????}?
?80?????????????????
?81?????????????????if(!roles.isEmpty()){?
?82?????????????????????????ConfigAttributeEditor?configAttrEditor=new?ConfigAttributeEditor();?
?83?????????????????????????StringBuffer?rolesStr=new?StringBuffer();?
?84?????????????????????????for(Iterator?it?=?roles.iterator();it.hasNext();){?
?85?????????????????????????????????GrantedAuthority?role=(GrantedAuthority)it.next();?
?86?????????????????????????????????rolesStr.append(role.getAuthority()).append(",");?
?87?????????????????????????}?
?88?
?89?????????????????????????configAttrEditor.setAsText(?rolesStr.toString().substring(0,rolesStr.length()-1)?);?
?90?????????????????????????ConfigAttributeDefinition?configAttrDef=(ConfigAttributeDefinition)configAttrEditor.getValue();?
?91?????????????????????????return?configAttrDef;?
?92?????????????????}?
?93?
?94?????????????????Assert.notEmpty(roles,"collection?of?roles?is?null?or?empty");?
?95?????????????????return?null;?
?96?????????????????
?97?
?98?????????}?
?99?
100?????????public?Iterator?getConfigAttributeDefinitions()?{?
101?????????????????
102?????????????????return?null;?
103?????????}?
104?
105?
106?????????public?IBaseDao?getBaseDao()?{?
107?????????????????return?baseDao;?
108?????????}?
109?
110?
111?????????public?void?setBaseDao(IBaseDao?baseDao)?{?
112?????????????????this.baseDao?=?baseDao;?
113?????????}?
114?
115?????????public?AuthorityBasedFunctionCache?getCache()?{?
116?????????????????return?cache;?
117?????????}?
118?
119?????????public?void?setCache(AuthorityBasedFunctionCache?cache)?{?
120?????????????????this.cache?=?cache;?
121?????????}?
122?
123?}?
124?
2:定義 基于方法的 自定義標志
通過以上的分析 , 要想使用acegi 做頁面的顯示控制僅僅靠角色(Role)是不行的,因為用戶可能隨時定義出新的角色,所以只能 基于方法(Function)的控制??墒莂cegi 只是提供了基于 角色的 接口GrantedAuthority ,怎么辦?? ,如法炮制。 首先定義出我們自己的GrantedFunction,實現也雷同 GrantedAuthorityImpl
?1?package?sample.auth;?
?2?
?3?import?java.io.Serializable;?
?4?public?class?GrantedFunctionImpl?implements?GrantedFunction?,?Serializable{?
?5?
?6?????private?String?function;?
?7?
?8?????//~?Constructors?===========================================================?
?9?
10?????public?GrantedFunctionImpl(String?function)?{?
11?????????super();?
12?????????this.function?=?function;?
13?????}?
14?
15?????protected?GrantedFunctionImpl()?{?
16?????????throw?new?IllegalArgumentException("Cannot?use?default?constructor");?
17?????}?
18?
19?????//~?Methods?================================================================?
20?
21?????public?String?getFunction()?{?
22?????????return?this.function;?
23?????}?
24?
25?????public?boolean?equals(Object?obj)?{?
26?????????if?(obj?instanceof?String)?{?
27?????????????return?obj.equals(this.function);?
28?????????}?
29?
30?????????if?(obj?instanceof?GrantedFunction)?{?
31?????????????GrantedFunction?attr?=?(GrantedFunction)?obj;?
32?
33?????????????return?this.function.equals(attr.getFunction());?
34?????????}?
35?
36?????????return?false;?
37?????}?
38?
39?????public?int?hashCode()?{?
40?????????return?this.function.hashCode();?
41?????}?
42?
43?????public?String?toString()?{?
44?????????return?this.function;?
45?????}?
46?
47?}?
48?
以下是我的標志實現,大致思路是 根據 頁面 的傳來的 方法名(即 FunctionName)查詢出對應的Functions,并且包裝成grantedFunctions ,然后根據用戶的角色查詢出用戶對應的Functions ,再取這兩個集合的交集,最后再根據這個集合是否為空判斷是否顯示標志體的內容。
??1?package?sample.auth;?
??2?import?java.util.Arrays;?
??3?import?java.util.Collection;?
??4?import?java.util.Collections;?
??5?import?java.util.HashSet;?
??6?import?java.util.Iterator;?
??7?import?java.util.List;?
??8?import?java.util.Set;?
??9?
?10?import?javax.servlet.jsp.JspException;?
?11?import?javax.servlet.jsp.tagext.Tag;?
?12?import?javax.servlet.jsp.tagext.TagSupport;?
?13?
?14?import?org.acegisecurity.Authentication;?
?15?import?org.acegisecurity.GrantedAuthority;?
?16?import?org.acegisecurity.context.SecurityContextHolder;?
?17?import?org.springframework.util.StringUtils;?
?18?import?org.springframework.web.util.ExpressionEvaluationUtils;?
?19?
?20?import?sample.web.action.AppContext;?
?21?/**?
?22?*?
?23?*?@author?limq?
?24?*?
?25?*/?
?26?public?class?AuthorizeActionTag?extends?TagSupport{?
?27?
?28?????????????private?String?ifAllGranted?=?"";?
?29?????????????private?String?ifAnyGranted?=?"";?
?30?????????????private?String?ifNotGranted?=?"";?
?31?????????????
?32?????????????public?void?setIfAllGranted(String?ifAllGranted)?throws?JspException?{?
?33?????????????????this.ifAllGranted?=?ifAllGranted;?
?34?????????????}?
?35?
?36?????????????public?String?getIfAllGranted()?{?
?37?????????????????return?ifAllGranted;?
?38?????????????}?
?39?
?40?????????????public?void?setIfAnyGranted(String?ifAnyGranted)?throws?JspException?{?
?41?????????????????this.ifAnyGranted?=?ifAnyGranted;?
?42?????????????}?
?43?
?44?????????????public?String?getIfAnyGranted()?{?
?45?????????????????return?ifAnyGranted;?
?46?????????????}?
?47?
?48?????????????public?void?setIfNotGranted(String?ifNotGranted)?throws?JspException?{?
?49?????????????????this.ifNotGranted?=?ifNotGranted;?
?50?????????????}?
?51?
?52?????????????public?String?getIfNotGranted()?{?
?53?????????????????return?ifNotGranted;?
?54?????????????}?
?55?????????????
?56?????????????public?int?doStartTag()?throws?JspException?{?
?57?????????????????if?(((null?==?ifAllGranted)?||?"".equals(ifAllGranted))?
?58?????????????????????&&?((null?==?ifAnyGranted)?||?"".equals(ifAnyGranted))?
?59?????????????????????&&?((null?==?ifNotGranted)?||?"".equals(ifNotGranted)))?{?
?60?????????????????????return?Tag.SKIP_BODY;?
?61?????????????????}?
?62?
?63?????????????????final?Collection?granted?=?getPrincipalFunctionByAuthorities();?
?64?
?65?????????????????final?String?evaledIfNotGranted?=?ExpressionEvaluationUtils?
?66?????????????????????.evaluateString("ifNotGranted",?ifNotGranted,?pageContext);?
?67?
?68?????????????????if?((null?!=?evaledIfNotGranted)?&&?!"".equals(evaledIfNotGranted))?{?
?69?????????????????????Set?grantedCopy?=?retainAll(granted,?
?70?????????????????????????????????????parseSecurityString(evaledIfNotGranted));?
?71?
?72?????????????????????if?(!grantedCopy.isEmpty())?{?
?73?????????????????????????return?Tag.SKIP_BODY;?
?74?????????????????????}?
?75?????????????????}?
?76?
?77?????????????????final?String?evaledIfAllGranted?=?ExpressionEvaluationUtils?
?78?????????????????????.evaluateString("ifAllGranted",?ifAllGranted,?pageContext);?
?79?
?80?????????????????if?((null?!=?evaledIfAllGranted)?&&?!"".equals(evaledIfAllGranted))?{?
?81?????????????????????if?(!granted.containsAll(parseSecurityString(evaledIfAllGranted)))?{?
?82?????????????????????????return?Tag.SKIP_BODY;?
?83?????????????????????}?
?84?????????????????}?
?85?
?86?????????????????final?String?evaledIfAnyGranted?=?ExpressionEvaluationUtils?
?87?????????????????????.evaluateString("ifAnyGranted",?ifAnyGranted,?pageContext);?
?88?
?89?????????????????if?((null?!=?evaledIfAnyGranted)?&&?!"".equals(evaledIfAnyGranted))?{?
?90?????????????????????Set?grantedCopy?=?retainAll(granted,?
?91?????????????????????????????????????parseSecurityString(evaledIfAnyGranted));?
?92?
?93?????????????????????if?(grantedCopy.isEmpty())?{?
?94?????????????????????????return?Tag.SKIP_BODY;?
?95?????????????????????}?
?96?????????????????}?
?97?
?98?????????????????return?Tag.EVAL_BODY_INCLUDE;?
?99?????????????}?
100?????/**?
101??????*?得到用戶的Authentication,并且從Authentication中獲得?Authorities,進而得到?授予用戶的?Function?
102??????*?@return?
103??????*/?
104?????????????private?Collection?getPrincipalFunctionByAuthorities()?{?
105?????????????????????
106?????????????????????
107?????????????Authentication?currentUser?=?SecurityContextHolder.getContext()?
108?????????????.getAuthentication();?
109?????????????????if?(null?==?currentUser)?{?
110?????????????????????return?Collections.EMPTY_LIST;?
111?????????????????}?
112?
113?????????????????if?((null?==?currentUser.getAuthorities())?
114?????????????????????||?(currentUser.getAuthorities().length?<?1))?{?
115?????????????????????return?Collections.EMPTY_LIST;?
116?????????????????}?
117????????????//?currentUser.getAuthorities()?返回的是?GrantedAuthority[]?
118?????????????????List?granted?=?Arrays.asList(currentUser.getAuthorities());?
119?????????????????AuthDao?authDao?=(AuthDao)?AppContext.getInstance().getAppContext().getBean("authDao");?
120?????????????????Collection?grantedFunctions?=?authDao.getFunctionsByRoles(granted);?
121?????????????????return?grantedFunctions;?
122?????????????}?
123?
124?????????????/**?
125??????????????*?得到用戶功能(Function)的集合,并且驗證是否合法?
126??????????????*?@param?c?Collection?類型?
127??????????????*?@return?Set類型?
128??????????????*/?
129?????????????private?Set?SecurityObjectToFunctions(Collection?c)?{?
130?????????????????Set?target?=?new?HashSet();?
131?
132?????????????????for?(Iterator?iterator?=?c.iterator();?iterator.hasNext();)?{?
133?????????????????????GrantedFunction?function?=?(GrantedFunction)?iterator.next();?
134?
135?????????????????????if?(null?==?function.getFunction())?{?
136?????????????????????????throw?new?IllegalArgumentException(?
137?????????????????????????????"Cannot?process?GrantedFunction?objects?which?return?null?from?getFunction()?-?attempting?to?process?"?
138?????????????????????????????+?function.toString());?
139?????????????????????}?
140?
141?????????????????????target.add(function.getFunction());?
142?????????????????}?
143?
144?????????????????return?target;?
145?????????????}?
146?
147?????????????/**?
148??????????????*?處理頁面標志屬性?,用'?,'區分?
149??????????????*/?
150?????????????private?Set?parseSecurityString(String?functionsString)?{?
151?????????????????final?Set?requiredFunctions?=?new?HashSet();?
152?????????????????final?String[]?functions?=?StringUtils?
153?????????????????????.commaDelimitedListToStringArray(functionsString);?
154?
155?????????????????for?(int?i?=?0;?i?<?functions.length;?i++)?{?
156?????????????????????String?authority?=?functions[i];?
157?
158??????????????????//?Remove?the?role's?whitespace?characters?without?depending?on?JDK?1.4+?
159??????????????????//?Includes?space,?tab,?new?line,?carriage?return?and?form?feed.?
160??????????????????String?function?=?StringUtils.replace(authority,?"?",?"");?
161??????????????????function?=?StringUtils.replace(function,?"\t",?"");?
162??????????????????function?=?StringUtils.replace(function,?"\r",?"");?
163??????????????????function?=?StringUtils.replace(function,?"\n",?"");?
164??????????????????function?=?StringUtils.replace(function,?"\f",?"");?
165?
166??????????????????requiredFunctions.add(new?GrantedFunctionImpl(function));?
167?????????????????}?
168?
169?????????????????return?requiredFunctions;?
170?????????????}?
171?????????????/**?
172??????????????*?獲得用戶所擁有的Function?和?要求的?Function?的交集?
173??????????????*?@param?granted?用戶已經獲得的Function?
174??????????????*?@param?required?所需要的Function?
175??????????????*?@return?
176??????????????*/?
177???????????
178?????????????private?Set?retainAll(final?Collection?granted,?final?Set?required)?{?
179?????????????????Set?grantedFunction?=?SecurityObjectToFunctions(granted);?
180?????????????????Set?requiredFunction?=?SecurityObjectToFunctions(required);?
181?????????????????//?retailAll()?獲得?grantedFunction?和?requiredFunction?的交集?
182?????????????????//?即刪除?grantedFunction?中??除了?requiredFunction?的項?
183?????????????????grantedFunction.retainAll(requiredFunction);?
184?
185?????????????????return?rolesToAuthorities(grantedFunction,?granted);?
186?????????????}?
187?
188?????????????/**?
189??????????????*?
190??????????????*?@param?grantedFunctions?已經被過濾過的Function????????????
191??????????????*?@param?granted?未被過濾過的,即用戶所擁有的Function?
192??????????????*?@return?
193??????????????*/?
194?????????????private?Set?rolesToAuthorities(Set?grantedFunctions,?Collection?granted)?{?
195?????????????????Set?target?=?new?HashSet();?
196?
197?????????????????for?(Iterator?iterator?=?grantedFunctions.iterator();?iterator.hasNext();)?{?
198?????????????????????String?function?=?(String)?iterator.next();?
199?
200?????????????????????for?(Iterator?grantedIterator?=?granted.iterator();?
201?????????????????????????grantedIterator.hasNext();)?{?
202?????????????????????????GrantedFunction?grantedFunction?=?(GrantedFunction)?grantedIterator?
203?????????????????????????????.next();?
204?
205?????????????????????????if?(grantedFunction.getFunction().equals(function))?{?
206?????????????????????????????target.add(grantedFunction);?
207?
208?????????????????????????????break;?
209?????????????????????????}?
210?????????????????????}?
211?????????????????}?
212?
213?????????????????return?target;?
214?????????????}?
215?}?
216?
217?
再說明一下吧,通過 AppContext 獲得了Spring的上下文,以及AuthDao(實際意義上講以不再是單純的Dao,應該是Service)
package?sample.auth;?

import?java.util.Collection;?

public?interface??AuthDao?
{?


????/**?*//**?
?????*??根據用戶的角色集合?得到?用戶的?操作權限?
?????*?@param?granted?已授予用戶的角色集合?
?????*?@return?操作權限的集合?
?????*/?
????????public?Collection?getFunctionsByRoles(Collection?granted);?
}?

以下是AuthDao 的實現
package?sample.auth;?
import?java.util.Collection;?
import?java.util.HashSet;?
import?java.util.Iterator;?
import?java.util.Set;?
import?org.acegisecurity.GrantedAuthority;?
import?sample.auth.cache.FunctionCache;?
import?sample.auth.cache.info.RoleByNameCache;?
import?sample.dao.IBaseDao;?
import?sample.mappings.function.Function;?
import?sample.mappings.role.Role;?
public?class?AuthDaoImpl??implements?AuthDao?{?
????private?IBaseDao?baseDao;?
????private?FunctionCache?cache;?
????private?RoleByNameCache?roleCache;?
????
????????public?RoleByNameCache?getRoleCache()?{?
????????????????return?roleCache;?
????????}?
????????public?void?setRoleCache(RoleByNameCache?roleCache)?{?
????????????????this.roleCache?=?roleCache;?
????????}?
????????public?FunctionCache?getCache()?{?
????????????????return?cache;?
????????}?
????????public?void?setCache(FunctionCache?cache)?{?
????????????????this.cache?=?cache;?
????????}?
????????public?IBaseDao?getBaseDao()?{?
????????return?baseDao;?
????}?
????public?void?setBaseDao(IBaseDao?baseDao)?{?
????????this.baseDao?=?baseDao;?
????}?
??
????????public?Collection?getFunctionsByRoles(Collection?granted)?{?
????????????????Set?set?=?new?HashSet();?
????????????????if(null?==?granted)?throw?new?IllegalArgumentException("Granted?Roles?cannot?be?null");?
????????
????????????????for(Iterator?it?=?granted.iterator();it.hasNext();){?
????????????
????????????GrantedAuthority?grantedAuthority?=?(GrantedAuthority)it.next();?
????????????Role??role?=?roleCache.getRoleByRoleNameCache(grantedAuthority.getAuthority());?//?
????????????if(role?==?null){?
????????????????????role?=?(Role)baseDao.loadByKey(Role.class,?"name",?grantedAuthority.getAuthority());?
????????????????????roleCache.putRoleInCache(role);?
????????????}?
????????????GrantedFunction[]?grantedFunctions?=?cache.getFunctionFromCache(role.getName());?
????????????
????????????if(grantedFunctions?==?null){?
????????????????????
????????????????????Set?functions?=?role.getFunctions();?
????????????????????????????for(Iterator?it2?=?functions.iterator();it2.hasNext();){????????
????????????????????Function?function?=?(Function)it2.next();?
????????????????????GrantedFunction?grantedFunction?=?new?GrantedFunctionImpl(function.getName());?
????????????????????????????????????set.add(??grantedFunction??);?
????????????????????????????}?
??????????????????
????????????????????????????grantedFunctions?=?(GrantedFunction[])?set.toArray(new?GrantedFunction[0]);?
????????????????????????????cache.putFuncitonInCache(role.getName(),grantedFunctions);?
????????????}?
????????????
????????????for(int?i?=?0?;?i?<?grantedFunctions.length;?i++){?
????????????????????GrantedFunction?grantedFunction?=?grantedFunctions[i];?
????????????????????set.add(grantedFunction);?
????????????}?
????????????????}?
????????
????????????????return?set;?
????????}?
}?
3 基于hibernate的用戶驗證
acegi 默認的 的 用戶驗證是 通過UserDetailsService 接口 實現的 也就是說我們只要實現了 它的loadUserByUsername 方法。
1?
2?public?UserDetails?loadUserByUsername(String?username)?
3?????????throws?UsernameNotFoundException,?DataAccessException;?
以下是我的實現
??1?package?sample.auth;?
??2?
??3?import?java.util.ArrayList;?
??4?import?java.util.Iterator;?
??5?import?java.util.List;?
??6?import?java.util.Set;?
??7?
??8?import?org.acegisecurity.GrantedAuthority;?
??9?import?org.acegisecurity.GrantedAuthorityImpl;?
?10?import?org.acegisecurity.userdetails.User;?
?11?import?org.acegisecurity.userdetails.UserDetails;?
?12?import?org.acegisecurity.userdetails.UserDetailsService;?
?13?import?org.acegisecurity.userdetails.UsernameNotFoundException;?
?14?import?org.springframework.dao.DataAccessException;?
?15?
?16?import?sample.auth.cache.AuthorityBasedUserCache;?
?17?import?sample.dao.IBaseDao;?
?18?import?sample.mappings.role.Role;?
?19?import?sample.utils.MisUtils;?
?20?
?21?public?class?HibernateDaoImpl?implements?UserDetailsService{?
?22?
?23?????????
?24?????????private?String?rolePrefix?=?"";?
?25?????????private?boolean?usernameBasedPrimaryKey?=?false;?
?26?????private?AuthorityBasedUserCache?cache;?
?27?
?28?????private?IBaseDao?baseDao;?
?29?
?30?????????public?String?getRolePrefix()?{?
?31?????????????????return?rolePrefix;?
?32?????????}?
?33?????????
?34?????????public?void?setRolePrefix(String?rolePrefix)?{?
?35?????????????????this.rolePrefix?=?rolePrefix;?
?36?????????}?
?37?????????
?38?????????public?UserDetails?loadUserByUsername(String?username)?throws?UsernameNotFoundException,?DataAccessException?{?
?39?????????????????UserDetails?user?=?getUsersByUsernameQuery(username);?
?40?????????????????if(user?==?null)?return?null;?
?41?????????????????
?42?????????????????GrantedAuthority[]?arrayAuths?=getAuthoritiesByUsernameQuery(username);?
?43??????????????if?(arrayAuths.length?==?0)?{?
?44?????????????????????throw?new?UsernameNotFoundException("User?has?no?GrantedAuthority");?
?45?????????????????}?
?46???????????????
?47??????????????return?new?User(username,?user.getPassword(),?user.isEnabled(),?
?48??????????????????????true,?true,?true,?arrayAuths);?
?49?????????}?
?50?
?51?????????/**?
?52?????????*?根據用戶名查找用戶?
?53?????????*?@param?username?
?54?????????*?@return?
?55?????????*?@throws?DataAccessException?
?56?????????*/?
?57?????????public?UserDetails?getUsersByUsernameQuery(String?username)throws?DataAccessException?{?
?58?????????????????????????sample.mappings.user.User?misUser?=?(sample.mappings.user.User)baseDao.loadByKey(sample.mappings.user.User.class,"name",username);?
?59?????????????????????????if(misUser?!=?null)?
?60?????????????????????????{?
?61?????????????????????????org.acegisecurity.userdetails.UserDetails?user?=?
?62?????????????????????????new?User(misUser.getName(),misUser.getPassword(),MisUtils.parseBoolean(misUser.getEnable()),true,true,true,getAuthoritiesByUsernameQuery(username));?
?63?????????????????????????return?user;?
?64?????????????????????????}else?
?65?????????????????????????return?null;????????
?66?????????????????}?
?67?????????
?68?????????/**?
?69???????????*?根據用戶名查找角色?
?70???????????*?@param?username?
?71???????????*?@return?GrantedAuthority[]?用戶角色?
?72???????????*?@throws?DataAccessException?
?73???????????*/?
?74?????????public?GrantedAuthority[]?getAuthoritiesByUsernameQuery(String?username)?
?75?????????????????throws?DataAccessException?{?
?76?????????????????sample.mappings.user.User?misUser?
?77?????????????????=?(sample.mappings.user.User)baseDao.loadByKey(sample.mappings.user.User.class,"name",username);?
?78?
?79?????????if(misUser?!=?null){?
?80?????????????????GrantedAuthority[]?grantedAuthoritys?=?cache.getAuthorityFromCache(misUser.getName());?
?81?????????
?82?????????????????if(grantedAuthoritys?==?null){?
?83?????????????????
?84?????????????????????????Set?roles?=?????misUser.getRoles();?
?85?????????????????????????Iterator?it?=?roles.iterator();?
?86?????????????????
?87?????????????????????????List?list?=?new?ArrayList();?
?88?????????????????????????while(it.hasNext()?){?
?89?????????
?90?????????????????????????????????GrantedAuthorityImpl?gai?=?new?GrantedAuthorityImpl(??((Role)it.next()).getName()??);?
?91?????????????????????????????????list.add(gai);?
?92?????????????????????????????????}?
?93?????????????????????????grantedAuthoritys?=(GrantedAuthority[])?list.toArray(new??GrantedAuthority[0]);?
?94?????????????????????????cache.putAuthorityInCache(misUser.getName(),grantedAuthoritys);?
?95?????????????????????????return?grantedAuthoritys;?
?96?????????????????
?97?????????????????}?
?98????????????????return?grantedAuthoritys;?
?99?????????}?
100?
101?????????????????return?null;?
102?}?
103?
104?????????public?IBaseDao?getBaseDao()?{?
105?????????????????return?baseDao;?
106?????????}?
107?
108?????????public?void?setBaseDao(IBaseDao?baseDao)?{?
109?????????????????this.baseDao?=?baseDao;?
110?????????}?
111?
112?????????public?AuthorityBasedUserCache?getCache()?{?
113?????????????????return?cache;?
114?????????}?
115?
116?????????public?void?setCache(AuthorityBasedUserCache?cache)?{?
117?????????????????this.cache?=?cache;?
118?????????}?
119?
120?}?
121?
通過以上對acegi 的 處理,足以滿足我們目前在spring下基于RBAC的動態權限管理。同時在對頻繁的數據庫查詢上使用了Ehcache作為緩存,在性能上有了很大的改善。
posted on 2006-12-03 16:04
西紅柿(tomato) 閱讀(1564)
評論(1) 編輯 收藏 所屬分類:
安全認證相關