权限管理之基于ACL的实现:讲解授权、认证、获得用户权限过程

时间:2022-07-29 15:24:09

权限管理模块的实现,需要多个用例:管理模块信息、管理用户信息、管理角色信息、给用户分配角色、给角色授权、给用户授权、获取用户授权列表、判断用户对某个模块的某操作是否允许授权

其中比较重要的是:授权、认证、获得用户拥有的所有授权。下面一一介绍:

 

授权过程

就是把系统现有模块授权给用户或角色

 

授权与取消授权的实现代码:

public void setPermission(int permission,boolean yes){  
int temp = 1;
temp = temp << permission;
if(yes){
aclState |= temp;
}else{
aclState &= ~temp;
}
}

 

比如,setPermission(2,true)表示授予 update 权限。

一个int temp = 1的临时变量, aclState为原始授权状态

tmp的二进制表示是: 00000000 00000000 0000000000000001 

将tmp左移2位得到updatetemp = tmp < < 2; temp变成:00000000 00000000 00000000 00000100 ,而第三位代表的就是Update权限。所以也能得出,左移0123就能得到CreateDeleteUpdateSelect权限。

 

假设原始授权aclState=00000000 00000000 0000000000001010 

当变量yes=true时,为授权,将temp与aclState求|运算,因为temp现在只有他要授权的位为1,求或运算后,aclState=0000000000000000 00000000 00001110,这样就授权成功

当变量yes=false时,为取消授权,先将temp取反,即为1111111111111111 11111111 11111011,现在只有要取消权限的位为0,其余全为1,然后与aclState求&运算,则除了要取消权限的位变0,其余的都不变,即aclState=0000000000000000 00000000 00001010

 

授权过程

权限管理之基于ACL的实现:讲解授权、认证、获得用户权限过程


/**
* 授权
* @param principalType主体类型
* @param principalSn 主体标识
* @param resourceSn 资源标识
* @param permission权限:C/R/U/D
* @param yes是否允许,true表示允许;false表示不允许
*/
public void addOrUpdatePermission(String principalType, intprincipalSn,
int resourceSn, int permission, boolean yes) {

//根据主体标识和资源标识查找ACL实例
ACL acl = findACL(principalType, principalSn, resourceSn);

//如果存在ACL实例,则更新其授权
if(acl != null){
acl.setPermission(permission, yes);
getHibernateTemplate().update(acl);
return;
}

//不存在ACL实例,则创建ACL实例
acl = new ACL();
acl.setPrincipalType(principalType);
acl.setPrincipalSn(principalSn);
acl.setResourceSn(resourceSn);
acl.setPermission(permission, yes);
getHibernateTemplate().save(acl);
}

认证过程

判断用户对某个模块的某操作是否是允许的


认证的实现代码:

public int getPermission(int permission){  

//如果继承,则返回未定的授权信息
if(aclTriState == 0xFFFFFFFF){
return ACL_NEUTRAL;
}

int temp = 1;
temp = temp << permission;

temp &= aclState;
if(temp != 0){
return ACL_YES;
}
return ACL_NO;
}

如果继承,则返回未定的授权信息,需要进一步根据角色判断。

否则,直接将temp变量与aclState求&,temp为1的位为要验证的权限,其余全为0,如果aclState对应的这一位为1,则结果不为零,即有该操作权限;若aclState这一位为0,则结果为0,即没有该操作权限

 

认证过程

权限管理之基于ACL的实现:讲解授权、认证、获得用户权限过程

/**
* 即时认证
* 判断用户对某模块的某操作的授权(允许或不允许)
* @param userId 用户标识
* @param reourceSn 资源标识
* @param permission 权限(C/R/U/D)
* @return 允许(true)或不允许(false)
*/
publicboolean hasPermission(int userId, int resourceSn, int permission) {

//查找直接授予用户的授权
ACLacl = findACL(ACL.TYPE_USER, userId, resourceSn);

if(acl!= null){
intyesOrNo = acl.getPermission(permission);

//如果是确定的授权
if(yesOrNo!= ACL.ACL_NEUTRAL){
returnyesOrNo == ACL.ACL_YES ? true : false;
}
}

//继续查找用户的角色授权(优先级别由高到低)
Stringhql = "select r.id from UsersRoles ur join ur.role r join ur.user u "+
"whereu.id = ? order by ur.orderNo asc";
ListaclIds = getHibernateTemplate().find(hql, userId);

//依照角色优先级依次查找其授权
for(Iterator iter = aclIds.iterator(); iter.hasNext();) {
Integerrid = (Integer) iter.next();
acl= findACL(ACL.TYPE_ROLE, rid, resourceSn);

//一旦发现授权,即可返回结果
if(acl!= null){
returnacl.getPermission(permission) == ACL.ACL_YES ? true : false;
}
}

returnfalse;
}


获得用户拥有的所有授权过程

在用户登陆系统之后,需要根据用户的被授权情况,允许用户对这些模块进行操作。

要获得用户拥有的所有授权,可以分四个步骤进行

1、查找授予用户拥有的角色的所有权限列表(按优先级从低到高查找)

2、查找直接授予用户的权限列表(所有不继承的权限)

3、将这些授权依次合并。在合并过程中,优先级高的授权将覆盖优先级低的授权;直接授予用户的授权将覆盖继承而来的授权,从而达到不继承的目的。

4、至此,可以得到用户的授权列表,删除那些没有读取权限的授权,即可得到最终的列表

 

/**
* 搜索某个用户拥有读取权限的模块列表(用于登录,形成导航菜单的时候)
* @param userId 用户标识
* @return 模块列表(即列表的元素是Module对象)
*/
publicList searchModules(int userId) {

//定义临时变量
Maptemp = new HashMap();

//按优先级从低到高查找用户拥有的角色
Stringhql = "select r.id from UsersRoles ur join ur.role r join ur.user u "+
"whereu.id = ? order by ur.orderNo desc";
ListaclIds = getHibernateTemplate().find(hql, userId);

//依次循环角色,合并权限,优先级高的授权将覆盖优先级低的授权
for(Iterator iter = aclIds.iterator(); iter.hasNext();) {
Integerrid = (Integer) iter.next();

//根据角色获得角色拥有的授权列表
Listacls = findRoleACLs(rid);

//把授权放入临时变量
for(Iterator iterator = acls.iterator(); iterator.hasNext();) {
ACLacl = (ACL) iterator.next();
//因为角色是按优先级从低到高遍历的,所以对于同一资源,优先级低的会被优先级高的覆盖
temp.put(acl.getResourceSn(),acl);
}
}

//查找直接授予用户的授权列表
Listacls = findUserACLs(userId);
for(Iterator iter = acls.iterator(); iter.hasNext();) {
ACLacl = (ACL) iter.next();
//同样,对于同一资源,会覆盖掉继承而来的权限,从而达到不继承的目的
temp.put(acl.getResourceSn(),acl);
}

//现在已获得用户拥有的所有授权(包括直接授予用户的以及用户继承角色的授权)
//遍历所有权限,如果没有读取权限,则在临时变量中删除这个授权

//遍历授权列表,如果没有读取权限,则临时存放在list中记录下来(map结构在遍历时进行remove操作会影响结果)
ListdelResources = new ArrayList();
Setentries = temp.entrySet();
for(Iterator iter = entries.iterator(); iter.hasNext();) {
Map.Entryentry = (Map.Entry) iter.next();
ACLacl = (ACL)entry.getValue();

if(acl.getPermission(Permission.READ)== ACL.ACL_NO){
delResources.add(entry.getKey());
}
}

//在临时变量中删除这些需要删除的授权
for(Iterator iter = delResources.iterator(); iter.hasNext();) {
Objectkey = (Object) iter.next();
temp.remove(key);
}

//如果授权列表是空的,则返回0长度的集合
if(temp.isEmpty()){
returnnew ArrayList();
}

//现在已获得用户拥有读取权限的授权
StringsearchModules = "select m from Module m where m.id in (:ids)";
returngetSession().createQuery(searchModules)
.setParameterList("ids",temp.keySet())
.list();
}

这是授权、认证、获得用户权限过程的实现过程,也是权限管理最主要最复杂的地方 ,请关注下篇文章