Blog信息 |
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7606468 建立时间:2006年5月29日 |

| |
[Hibernate]Acegi+hibernate 动态实现基于角色的权限管理(2) 软件技术, 电脑与网络
lhwork 发表于 2006/6/13 11:32:58 |
解决方法: 1: 开发基于数据库的保护资源。 看过acegi的源代码就会知道,对保护资源的定义是通过实现ObjectDefinitionSource这个接口来实现的,而且acegi为我们提供了默认实现的抽象类
500)this.width=500'>public abstract class AbstractMethodDefinitionSource 500)this.width=500'>500)this.width=500'> implements MethodDefinitionSource 500)this.width=500'>{ 500)this.width=500'> //~ Static fields/initializers ============================================= 500)this.width=500'>500)this.width=500'> private static final Log logger = LogFactory.getLog(AbstractMethodDefinitionSource.class); 500)this.width=500'>500)this.width=500'> //~ Methods ================================================================ 500)this.width=500'>500)this.width=500'> public ConfigAttributeDefinition getAttributes(Object object) 500)this.width=500'>500)this.width=500'> throws IllegalArgumentException 500)this.width=500'>{ 500)this.width=500'> Assert.notNull(object, "Object cannot be null"); 500)this.width=500'>500)this.width=500'>500)this.width=500'> if (object instanceof MethodInvocation) 500)this.width=500'>{ 500)this.width=500'> return this.lookupAttributes(((MethodInvocation) object).getMethod()); 500)this.width=500'> } 500)this.width=500'>500)this.width=500'>500)this.width=500'> if (object instanceof JoinPoint) 500)this.width=500'>{ 500)this.width=500'> JoinPoint jp = (JoinPoint) object; 500)this.width=500'> Class targetClazz = jp.getTarget().getClass(); 500)this.width=500'> String targetMethodName = jp.getStaticPart().getSignature().getName(); 500)this.width=500'> Class[] types = ((CodeSignature) jp.getStaticPart().getSignature()) 500)this.width=500'> .getParameterTypes(); 500)this.width=500'>500)this.width=500'>500)this.width=500'> if (logger.isDebugEnabled()) 500)this.width=500'>{ 500)this.width=500'> logger.debug("Target Class: " + targetClazz); 500)this.width=500'> logger.debug("Target Method Name: " + targetMethodName); 500)this.width=500'>500)this.width=500'>500)this.width=500'> for (int i = 0; i < types.length; i++) 500)this.width=500'>{ 500)this.width=500'>500)this.width=500'> if (logger.isDebugEnabled()) 500)this.width=500'>{ 500)this.width=500'> logger.debug("Target Method Arg #" + i + ": " 500)this.width=500'> + types[i]); 500)this.width=500'> } 500)this.width=500'> } 500)this.width=500'> } 500)this.width=500'>500)this.width=500'>500)this.width=500'> try 500)this.width=500'>{ 500)this.width=500'> return this.lookupAttributes(targetClazz.getMethod(targetMethodName, types)); 500)this.width=500'>500)this.width=500'> } catch (NoSuchMethodException nsme) 500)this.width=500'>{ 500)this.width=500'> throw new IllegalArgumentException("Could not obtain target method from JoinPoint: " + jp); 500)this.width=500'> } 500)this.width=500'> } 500)this.width=500'>500)this.width=500'> throw new IllegalArgumentException("Object must be a MethodInvocation or JoinPoint"); 500)this.width=500'> } 500)this.width=500'>500)this.width=500'>500)this.width=500'> public boolean supports(Class clazz) 500)this.width=500'>{ 500)this.width=500'> return (MethodInvocation.class.isAssignableFrom(clazz) 500)this.width=500'> || JoinPoint.class.isAssignableFrom(clazz)); 500)this.width=500'> } 500)this.width=500'>500)this.width=500'>500)this.width=500'> protected abstract ConfigAttributeDefinition lookupAttributes(Method method); 500)this.width=500'>} 500)this.width=500'>我们要做的就是实现它的 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)的控制。可是acegi 只是提供了基于 角色的 接口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 |
|
|