论坛首页 Java版 企业应用

一个rbac的权限管理模型,大家讨论讨论

浏览 11317 次
该帖已经被评为精华帖
作者 正文
最后更新时间:2005-08-04
基于简洁的原因,模型中的role没有层次结构。
   
最后更新时间:2005-08-05
我也用代码简单写一下,在Permission/Resource那里没这么多关系,Role扩展了一下,分三类角色,全局/非全局/归属具体Group。
接口定义:
[code:1]public interface SecurityRole extends SecurityObject {
    public List getScorpioleonPermissions();
    public List getSecurityUsers();
    public SecurityGroup getSecurityGroup();
    public boolean isGlobalRole();
}

public interface SecurityGroup extends SecurityObject {
    public List getSecurityUsers();
}

public interface SecurityUser extends SecurityObject {
    public SecurityGroup getSecurityGroup();
    public List getSecurityRoles();
}

public interface ScorpioleonPermission extends SecurityObject {
    public boolean equals(String operationIndentity, String resourceClassName);
    public boolean isAnonymousPermission(String operationIndentity, String resourceClassName);
}

public interface SecurityOperation extends SecurityObject {
    public String getIdentity();
    public SecurityOperation getInstance(String operationIdentity);
}

public interface SecurityResource extends SecurityObject {
    public SecurityGroup getSecurityGroup();
    public Class getSecurityClass();
}[/code:1]

service code:
[code:1]public class SecurityManager {
   
    private ScorpioleonPermission scorpioleonPermission;
   
    public void setPermission(ScorpioleonPermission scorpioleonPermission) {
        this.scorpioleonPermission = scorpioleonPermission;
    }

    public boolean hasPermission(SecurityUser user, SecurityOperation operation, SecurityResource resource) {
        return validate(resource) ? hasPermission(user, operation, resource, resource.getSecurityGroup()) : false;
    }
   
    public boolean hasPermission(SecurityUser user, SecurityOperation operation, SecurityResource resource, SecurityGroup group) {
        return validate(resource) ? hasPermission(user, operation, resource.getSecurityClass().getName(), group) : false;
    }
   
    public boolean hasPermission(SecurityUser user, SecurityOperation operation, String resourceClassName, SecurityGroup group) {
        if (!(validate(operation) && resourceClassName != null)) {
            return false;
        }
        if (scorpioleonPermission.isAnonymousPermission(operation.getIdentity(), resourceClassName)) {
            return true;
        }
        if (!(validate(user) && validate(group))) {
            return false;
        }
        List roles = user.getSecurityRoles();
        if (roles != null) {
            for (int i = roles.size() - 1; i >= 0; i--) {
                SecurityRole role = (SecurityRole)roles.get(i);
                if (role.isAvailable()) {
                    if (hasPermission(role, operation.getIdentity(), resourceClassName)) {
                        if (role.getSecurityGroup() != null) {
                            if (role.getSecurityGroup().equals(group)) {
                                return true;
                            }
                        } else if (role.isGlobalRole()) {
                            return true;
                        } else if (user.getSecurityGroup().equals(group)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
   
    public boolean hasPermission(SecurityRole role, String operationIndentity, String resourceClassName) {
        return role == null ? false : containPermission(role.getScorpioleonPermissions(), operationIndentity, resourceClassName);
    }
  
    protected boolean validate(SecurityObject securityObject) {
        return (securityObject != null && securityObject.isAvailable()) ? true : false;
    }

    public boolean containPermission(List permissions, String operationIndentity, String resourceClassName) {
        if (permissions == null) {
            return false;
        }
        for (int i = permissions.size() - 1; i >= 0; i++) {
            ScorpioleonPermission rolePermission = (ScorpioleonPermission)permissions.get(i);
            if (rolePermission.isAvailable() && rolePermission.equals(operationIndentity, resourceClassName)) {
                return true;
            }
        }
        return false;
    }
   
}[/code:1]

接下来之需要实现对应的接口以及为AOP编写SecurityInterceptor了
   
0 请登录后投票
最后更新时间:2005-08-05
lllyq:
你的模型对类进行了保护,而上面的模型对类的实例进行了保护。
但是,我们在很多时候是需要对类的实例进行保护的。
看看能不能综合一下,既考虑粗粒度的类保护,又考虑细粒度的类实例保护。
   
0 请登录后投票
最后更新时间:2005-08-05
那就拓展一下:
[code:1]public interface SecurityResource extends SecurityObject {
    public SecurityGroup getSecurityGroup();
    public Class getSecurityClass();
}[/code:1]
改为
[code:1]public interface SecurityResource extends SecurityObject {
    public String getIdentity();
    public SecurityGroup getSecurityGroup();
    public Class getSecurityClass();
}[/code:1]

SecurityManager 增加方法
例如对应于
[code:1]public boolean hasPermission(SecurityUser user, SecurityOperation operation, SecurityResource resource) ;[/code:1]
可有
[code:1]public boolean hasPermission(SecurityUser user, SecurityOperation operation, SecurityResource resource, String resourceIdentity)  {
    if (hasPermission(SecurityUser user, SecurityOperation operation, SecurityResource resource) {
        return true;
    } else {
         .......permission.equals(operationIdentity, resourceClassName, resourceIdentity);
         ......
    }

}[/code:1]
   
0 请登录后投票
最后更新时间:2005-08-06
lllyq:
你的模型很简洁,但有一点不尽如人意的地方。
在你的模型中,resource和operation是分开的。
而resource和operation实际上是相关的。比如说,对于一个工作流的流程,有开始、终止、任务分配等权限,而这些权限跟其他资源的权限显然不同,不能应用到其他资源上。这就需要管理员有相关的经验,才不会在分配权限时出错。
   
0 请登录后投票
最后更新时间:2005-08-07
jander 写道
lllyq:
你的模型很简洁,但有一点不尽如人意的地方。
在你的模型中,resource和operation是分开的。
而resource和operation实际上是相关的。比如说,对于一个工作流的流程,有开始、终止、任务分配等权限,而这些权限跟其他资源的权限显然不同,不能应用到其他资源上。这就需要管理员有相关的经验,才不会在分配权限时出错。

有很多方法可以控制某个资源允许有哪些操作,你也可以给ecurityResource加上getAvariableOperators(),不过我觉得还不如在管理权限的地方用getAvariableOperatorsByResource(SecurityResource resource)会好一点,因为这部分配资源的功能是相对独立的,可以不必在这个模型中反映,所以我觉得不必修改模型
   
0 请登录后投票
最后更新时间:2005-08-07
lllyq 写道

有很多方法可以控制某个资源允许有哪些操作,你也可以给ecurityResource加上getAvariableOperators(),不过我觉得还不如在管理权限的地方用getAvariableOperatorsByResource(SecurityResource resource)会好一点,因为这部分配资源的功能是相对独立的,可以不必在这个模型中反映,所以我觉得不必修改模型

Operation和Resource有关系,当然要反映出来。

另外,我觉得你的模型,从角色出发定义角色各个资源的权限很方便。但是,要从资源开始,定义一个资源的相关角色的权限就麻烦了。比如说,我要定义一个目录的权限,应该从目录管理中来定义。而不是从角色管理中来定义,因为方便一些。
还有,执行起来也没有我提出来的模型有效率。在你的模型中一个权限的相关操作在数据库中是一个集合,而我提出的模型中,一个权限在数据库中的相关操作仅仅用一个整形的mask标记。
   
0 请登录后投票
最后更新时间:2005-08-08
Operation和Resource不是必然关系,可以在实现类自定义。

引用
“定义一个目录的权限,应该从目录管理中来定义”

你是指授权给role还是直接授权给user,授权给role跟role获得resource的权限没什么差别。要是授权给user,那就不是纯rbac了,模型中的SecurityUser需要加getPermissions的方法,SecurityManager需要多一点判断,不难。

另外,int mask效率高,我想map role,group, resource type的信息还可以(我觉得也不好扩展),但是map resource id(细粒度),位数恐怕不够吧?
   
0 请登录后投票
最后更新时间:2005-08-08
lllyq 写道
Operation和Resource不是必然关系,可以在实现类自定义。

你是指在Resource的实现类中定义?


lllyq 写道
你是指授权给role还是直接授权给user,授权给role跟role获得resource的权限没什么差别。要是授权给user,那就不是纯rbac了,模型中的SecurityUser需要加getPermissions的方法,SecurityManager需要多一点判断,不难。

我是说,在你的模型中,从某个资源得到各个角色的授权情况,比较麻烦。
lllyq 写道

另外,int mask效率高,我想map role,group, resource type的信息还可以(我觉得也不好扩展),但是map resource id(细粒度),位数恐怕不够吧?

mask仅仅表示操作,看看上面的模型,每一类资源都有一个相应的Permission的子类,角色对一个资源的操作权限,仅仅用一个int类型的mask就表示了。下面是Permissiion的源码。

另外,下面简单画了一下你的模型。去除了Group和Role之间的关系,因为主要注意的是授权模型。在你的模型中,只需要编写一个Permission类就可以了,不知道我理解的对不对?
[code:1]

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* Class represents permissions on any {@link SecuredObject}. Every type of {@link SecuredObject}must has own subclass of this class which represent set of allowed permissions.
*
* @author Gordienko_m
* @author Semochkin_v
*/

public class Permission implements Serializable {
private static byte MASK_POWER = 0;

public static final Permission READ = new Permission(MASK_POWER++, "permission.read");

public static final Permission UPDATE_PERMISSIONS = new Permission(MASK_POWER++, "permission.update_permissions");

private static final Permission[] ALL_PERMISSIONS = { READ, UPDATE_PERMISSIONS };

private static final String NO_PERMISSION_NAME = "permission.none";

private String name;

private long mask;

protected Permission(byte maskPower, String name) {
this.mask = mask(maskPower++);
this.name = name;
}

/**
* Creates permission with mask==0
*/
public Permission() {
this.mask = 0;
this.name = NO_PERMISSION_NAME;
}

public long getMask() {
return mask;
}

public String getName() {
return name;
}

private static final long mask(long maskPower) {
return (long) Math.pow(2, maskPower);
}

public static long getMask(Permission[] per) {
long mask = 0;
for (int i = 0; i < per.length; i++) {
mask |= per[i].getMask();
}
return mask;
}

public Permission[] getPermissions(long mask) {
List permissionsList = new ArrayList();
Permission[] p = getAllPermissions();
for (int i = 0; i < p.length; i++) {
if ((mask & p[i].getMask()) == p[i].getMask()) {
permissionsList.add(p[i]);
}
}
return (Permission[]) permissionsList.toArray(new Permission[permissionsList.size()]);
}

/**
* Returns an array of all permissions that executor may have on type of secured object this class represents. This method must be overriden in subclass
*/
public Permission[] getAllPermissions() {
return (Permission[]) ALL_PERMISSIONS.clone();
}

public boolean equals(Object obj) {
if (obj == null)
return false;
if (this == obj)
return true;
if (!(this.getClass().isInstance(obj)))
return false;
Permission p = (Permission) obj;

if (getMask() == p.getMask() && getName().equals(p.getName()))
return true;

return false;
}

public int hashCode() {
int result = 17;
result = 37 * result + (int) (getMask() ^ (getMask() >>> 32));
result = 37 * result + getName().hashCode();
return result;
}

public String toString() {
return mask + " " + name;
}

public static Permission[] mergePermissions(Permission[] p1, Permission[] p2) {
Set set = new HashSet(Arrays.asList(p1));
set.addAll(Arrays.asList(p2));
return (Permission[]) set.toArray(new Permission[set.size()]);
}

public static Permission[] subtractPermissions(Permission[] p1, Permission[] p2) {
Set set = new HashSet(Arrays.asList(p1));
set.removeAll(Arrays.asList(p2));
return (Permission[]) set.toArray(new Permission[set.size()]);
}

}

[/code:1]
   
0 请登录后投票
最后更新时间:2005-09-22
我最近也在看权限方面的设计,很多地方不是很明白

楼上,你的模型里面的Group,感觉没有什么作用啊?

Group难道就是单纯的归类Users?

看到很多介绍权限的所谓的高手的文章,都提到Group和Operator是多对多的

但是,我看不到Group是怎么和Operator联系起来的阿?

请指点
   
0 请登录后投票
论坛首页 Java版 企业应用

跳转论坛:
JavaEye推荐