论坛首页 Java企业应用论坛

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

浏览 19391 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-08-04  
基于简洁的原因,模型中的role没有层次结构。
   发表时间:2005-08-05  
我也用代码简单写一下,在Permission/Resource那里没这么多关系,Role扩展了一下,分三类角色,全局/非全局/归属具体Group。
接口定义:
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();;
}


service code:
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;
    }
    
}


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

改为
public interface SecurityResource extends SecurityObject { 
    public String getIdentity();;
    public SecurityGroup getSecurityGroup();; 
    public Class getSecurityClass();; 
}


SecurityManager 增加方法
例如对应于
public boolean hasPermission(SecurityUser user, SecurityOperation operation, SecurityResource resource); ;

可有
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);;
         ......
    }

}
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类就可以了,不知道我理解的对不对?

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();]);;
	}

}

0 请登录后投票
   发表时间:2005-09-22  
我最近也在看权限方面的设计,很多地方不是很明白

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

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

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

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

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

跳转论坛:
Global site tag (gtag.js) - Google Analytics