Acegi+hibernate 动态实现基于角色的权限管理
Acegi+hibernate 动态实现基于角色的权限管理
以下是我的标志实现,大致思路是 根据 页面 的传来的 方法名(即 FunctionName)查询出对应的Functions,并且包装成grantedFunctions ,然后根据用户的角色查询出用户对应的Functions ,再取这两个集合的交集,最后再根据这个集合是否为空判断是否显示标志体的内容。
java代码: |
package sample.auth; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; import org.acegisecurity.Authentication; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.context.SecurityContextHolder; import org.springframework.util.StringUtils; import org.springframework.web.util.ExpressionEvaluationUtils; import sample.web.action.AppContext; /** * * @author limq * */ public class AuthorizeActionTag extends TagSupport{ private String ifAllGranted = ""; private String ifAnyGranted = ""; private String ifNotGranted = ""; public void setIfAllGranted(String ifAllGranted) throws JspException { this.ifAllGranted = ifAllGranted; } public String getIfAllGranted() { return ifAllGranted; } public void setIfAnyGranted(String ifAnyGranted) throws JspException { this.ifAnyGranted = ifAnyGranted; } public String getIfAnyGranted() { return ifAnyGranted; } public void setIfNotGranted(String ifNotGranted) throws JspException { this.ifNotGranted = ifNotGranted; } public String getIfNotGranted() { return ifNotGranted; } public int doStartTag() throws JspException { if (((null == ifAllGranted) || "".equals(ifAllGranted)) && ((null == ifAnyGranted) || "".equals(ifAnyGranted)) && ((null == ifNotGranted) || "".equals(ifNotGranted))) { return Tag.SKIP_BODY; } final Collection granted = getPrincipalFunctionByAuthorities(); final String evaledIfNotGranted = ExpressionEvaluationUtils .evaluateString("ifNotGranted", ifNotGranted, pageContext); if ((null != evaledIfNotGranted) && !"".equals(evaledIfNotGranted)) { Set grantedCopy = retainAll(granted, parseSecurityString(evaledIfNotGranted)); if (!grantedCopy.isEmpty()) { return Tag.SKIP_BODY; } } final String evaledIfAllGranted = ExpressionEvaluationUtils .evaluateString("ifAllGranted", ifAllGranted, pageContext); if ((null != evaledIfAllGranted) && !"".equals(evaledIfAllGranted)) { if (!granted.containsAll(parseSecurityString(evaledIfAllGranted))) { return Tag.SKIP_BODY; } } final String evaledIfAnyGranted = ExpressionEvaluationUtils .evaluateString("ifAnyGranted", ifAnyGranted, pageContext); if ((null != evaledIfAnyGranted) && !"".equals(evaledIfAnyGranted)) { Set grantedCopy = retainAll(granted, parseSecurityString(evaledIfAnyGranted)); if (grantedCopy.isEmpty()) { return Tag.SKIP_BODY; } } return Tag.EVAL_BODY_INCLUDE; } /** * 得到用户的Authentication,并且从Authentication中获得 Authorities,进而得到 授予用户的 Function * @return */ private Collection getPrincipalFunctionByAuthorities() { Authentication currentUser = SecurityContextHolder.getContext() .getAuthentication(); if (null == currentUser) { return Collections.EMPTY_LIST; } if ((null == currentUser.getAuthorities()) || (currentUser.getAuthorities().length < 1)) { return Collections.EMPTY_LIST; } // currentUser.getAuthorities() 返回的是 GrantedAuthority[] List granted = Arrays.asList(currentUser.getAuthorities()); AuthDao authDao =(AuthDao) AppContext.getInstance().getAppContext().getBean("authDao"); Collection grantedFunctions = authDao.getFunctionsByRoles(granted); return grantedFunctions; } /** * 得到用户功能(Function)的集合,并且验证是否合法 * @param c Collection 类型 * @return Set类型 */ private Set SecurityObjectToFunctions(Collection c) { Set target = new HashSet(); for (Iterator iterator = c.iterator(); iterator.hasNext();) { GrantedFunction function = (GrantedFunction) iterator.next(); if (null == function.getFunction()) { throw new IllegalArgumentException( "Cannot process GrantedFunction objects which return null from getFunction() - attempting to process " + function.toString()); } target.add(function.getFunction()); } return target; } /** * 处理页面标志属性 ,用' ,'区分 */ private Set parseSecurityString(String functionsString) { final Set requiredFunctions = new HashSet(); final String[] functions = StringUtils .commaDelimitedListToStringArray(functionsString); for (int i = 0; i < functions.length; i++) { String authority = functions[i]; // Remove the role's whitespace characters without depending on JDK 1.4+ // Includes space, tab, new line, carriage return and form feed. String function = StringUtils.replace(authority, " ", ""); function = StringUtils.replace(function, "\t", ""); function = StringUtils.replace(function, "\r", ""); function = StringUtils.replace(function, "\n", ""); function = StringUtils.replace(function, "\f", ""); requiredFunctions.add(new GrantedFunctionImpl(function)); } return requiredFunctions; } /** * 获得用户所拥有的Function 和 要求的 Function 的交集 * @param granted 用户已经获得的Function * @param required 所需要的Function * @return */ private Set retainAll(final Collection granted, final Set required) { Set grantedFunction = SecurityObjectToFunctions(granted); Set requiredFunction = SecurityObjectToFunctions(required); // retailAll() 获得 grantedFunction 和 requiredFunction 的交集 // 即删除 grantedFunction 中 除了 requiredFunction 的项 grantedFunction.retainAll(requiredFunction); return rolesToAuthorities(grantedFunction, granted); } /** * * @param grantedFunctions 已经被过滤过的Function * @param granted 未被过滤过的,即用户所拥有的Function * @return */ private Set rolesToAuthorities(Set grantedFunctions, Collection granted) { Set target = new HashSet(); for (Iterator iterator = grantedFunctions.iterator(); iterator.hasNext();) { String function = (String) iterator.next(); for (Iterator grantedIterator = granted.iterator(); grantedIterator.hasNext();) { GrantedFunction grantedFunction = (GrantedFunction) grantedIterator .next(); if (grantedFunction.getFunction().equals(function)) { target.add(grantedFunction); break; } } } return target; } } |
再说明一下吧,通过 AppContext 获得了Spring的上下文,以及AuthDao(实际意义上讲以不再是单纯的Dao,应该是Service)
java代码: |
package sample.auth; import java.util.Collection; public interface AuthDao { /** * 根据用户的角色集合 得到 用户的 操作权限 * @param granted 已授予用户的角色集合 * @return 操作权限的集合 */ public Collection getFunctionsByRoles(Collection granted); } |
以下是AuthDao 的实现
java代码: |
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 方法。
java代码: |
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException; |
以下是我的实现
java代码: |
package sample.auth; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.userdetails.User; import org.acegisecurity.userdetails.UserDetails; import org.acegisecurity.userdetails.UserDetailsService; import org.acegisecurity.userdetails.UsernameNotFoundException; import org.springframework.dao.DataAccessException; import sample.auth.cache.AuthorityBasedUserCache; import sample.dao.IBaseDao; import sample.mappings.role.Role; import sample.utils.MisUtils; public class HibernateDaoImpl implements UserDetailsService{ private String rolePrefix = ""; private boolean usernameBasedPrimaryKey = false; private AuthorityBasedUserCache cache; private IBaseDao baseDao; public String getRolePrefix() { return rolePrefix; } public void setRolePrefix(String rolePrefix) { this.rolePrefix = rolePrefix; } public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { UserDetails user = getUsersByUsernameQuery(username); if(user == null) return null; GrantedAuthority[] arrayAuths =getAuthoritiesByUsernameQuery(username); if (arrayAuths.length == 0) { throw new UsernameNotFoundException("User has no GrantedAuthority"); } return new User(username, user.getPassword(), user.isEnabled(), true, true, true, arrayAuths); } /** * 根据用户名查找用户 * @param username * @return * @throws DataAccessException */ public UserDetails getUsersByUsernameQuery(String username)throws DataAccessException { sample.mappings.user.User misUser = (sample.mappings.user.User)baseDao.loadByKey(sample.mappings.user.User.class,"name",username); if(misUser != null) { org.acegisecurity.userdetails.UserDetails user = new User(misUser.getName(),misUser.getPassword(),MisUtils.parseBoolean(misUser.getEnable()),true,true,true,getAuthoritiesByUsernameQuery(username)); return user; }else return null; } /** * 根据用户名查找角色 * @param username * @return GrantedAuthority[] 用户角色 * @throws DataAccessException */ public GrantedAuthority[] getAuthoritiesByUsernameQuery(String username) throws DataAccessException { sample.mappings.user.User misUser = (sample.mappings.user.User)baseDao.loadByKey(sample.mappings.user.User.class,"name",username); if(misUser != null){ GrantedAuthority[] grantedAuthoritys = cache.getAuthorityFromCache(misUser.getName()); if(grantedAuthoritys == null){ Set roles = misUser.getRoles(); Iterator it = roles.iterator(); List list = new ArrayList(); while(it.hasNext() ){ GrantedAuthorityImpl gai = new GrantedAuthorityImpl( ((Role)it.next()).getName() ); list.add(gai); } grantedAuthoritys =(GrantedAuthority[]) list.toArray(new GrantedAuthority[0]); cache.putAuthorityInCache(misUser.getName(),grantedAuthoritys); return grantedAuthoritys; } return grantedAuthoritys; } return null; } public IBaseDao getBaseDao() { return baseDao; } public void setBaseDao(IBaseDao baseDao) { this.baseDao = baseDao; } public AuthorityBasedUserCache getCache() { return cache; } public void setCache(AuthorityBasedUserCache cache) { this.cache = cache; } } 通过以上对acegi 的 处理,足以满足我们目前在spring下基于RBAC的动态权限管理。同时在对频繁的数据库查询上使用了Ehcache作为缓存,在性能上有了很大的改善。 |