您的位置:首页 > 其它

权限管理 (一) 设计思路分析和实现授权、认证

2013-11-24 13:50 393 查看
权限的认识

说起对权限的理解可以说是从肤浅到了解,现在也只是处在了解的水平,先来看这样一个通俗且真实的故事:我们都知道在有体制的公司或者机关单位,给人的体制化特别突出,通俗的说就是官大一级压死人,上级的权利往往要比下面人大,有什么事情了需要经过上级审批、同意才能够执行,这也是一种法律程序,很多事情都需要走法律流程。

你没有在领导的位置上有些事情你说了就不算需要领导同意,如果某天你的上司说“这件事你说了算,由你负责”这就是把管这事的权利交给你,叫授权;然后,和这件事打交道的人员需要确认谁管这事,这就叫做认证。权限也就是授权和认证的过程。

在做机房系统中同样也涉及到了权限,系统中分了三类人员管理员、操作员和一般用户,需要根据不同类型的人员显示不同的界面模块,当初实现的时候仅仅是在界面层做了一个简单的判断做的非常粗糙,只是简单的显示出人员对应的模块没有深入的进行控制,如一个模块的增删改查控制,如果该人员对应的模块显示出来了就会有该模块的所有权限,不够灵活。

随着做的系统逐步变大、模块也增多了我们引入了角色一词表示一组权限的集合,相当于根据实际需求把权限分了“类”分成一组一组的,可以将一组权限授予用户,如此一来,不需要一个个的授予用户变的方便了。当然也可以给某一个用户单独授权。

权限设计的目标是设计出这样的系统界面:用户授权、认证、模块动态显示等,这部分对于系统的安全性至关重要,因此,权限设计非常重要,也有一些成熟的模型解决权限管理,下面我们来介绍一种实现解决方案:

实现思路和需求

把各个模块、角色、用户抽象出来各对应一个实体类,让用户或角色与模块关联并增加属性控制增删改查,这很像是一个M:N的对应关系又往中间一个关系上添加属性,授权的过程中主要通过角色给用户授权,特殊的也可以给用户单独授权。

用户(User)可以拥有多个角色(Role),角色可以被分配给多个用户

权限的意思就是对某个资源的某个操作,现在规定:

所谓资源,即系统的模块

所谓操作,包括:增加、删除、修改、查询等操作

权限管理系统的总体功能分为:授权与认证

授权,指将权限授予角色或用户

如果用户A拥有角色B、角色C,那么,缺省的情况下,用户A将拥有被分配给角色A和角色C的所有权限(即默认情况下,用户A继承其拥有的角色所具有的所有权限)

如果用户拥有多个角色,那么用户的权限是这些角色权限的合集

如果用户拥有多个角色,而且角色之间的授权有冲突(比如对同一个资源的同一个操作,一个角色为“允许”,另外一个角色为“不允许”),将以优先级别高的角色为准(所谓优先级别,也就是对于这个用户所拥有的角色而言,是有顺序的,同一个角色在不同的用户那里可能拥有不同的优先级)

除了可以对角色进行授权外,也可以针对用户进行授权,也就是说,将权限授予用户。针对某个资源的所有操作,我们可以设置这些权限对用户来说是“继承”或“不继承”

继承:意思是这些权限将使用其(即用户)所拥有的角色的权限,而不使用其(即用户)单独设置的权限

不继承:意思是这些权限将使用其单独设置的权限,而不使用其所拥有的角色的权限

认证,指用户访问资源的某些操作时,根据授权,判断是否允许用户的访问

在用户访问的时候,需要进行即时的判断(是否有权访问)

应该提供查询的功能,可以查询某个用户所拥有的所有权限

抽象实体类

为了实现生面需求,抽象出来了下面这些实体类,这张类图是主要的实体对象,可以实现权限控制。

图ACL

图中主要不易理解的是ACL类,该类表示访问控制列表(access
control list),具有用户或角色与模块的关联关系以及它们的操作标识符,其中,操作标识符利用int的二进制表示,java中int为32位可以用其中任意四位代表CRUD,为了方便一些使用最右边四位表示,表示是否有操作权限。

用户还可以从角色那里继承权限,我们在ACL类中新增加一个int属性表示角色是否被继承,在UsersRoles关系中加入一个字段代表角色的优先级,解决不同角色拥有相同模块时的冲突问题。

实现

授权的过程即把模块的访问权授予用户或者角色。

某一模块授权或者取消授权的代码

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


例如setPermission(1,true)表示授予
read 权限,一个int temp = 1的临时变量, aclState为原始授权状态,tmp的二进制表示是:
00000000 00000000 0000000000000001,将tmp左移1位得到read。temp = tmp < < 1; temp变成:00000000 00000000 00000000 00000010,而第二位代表的就是read权限。所以也能得出,左移0、1、2、3就能得到Create、Delete、Update、Select权限。

假设原始授权aclState=00000000 00000000 0000000000001010,当变量yes=true时,为授权,将temp与aclState求|运算,因为temp现在只有他要授权的位为1,求或运算后,aclState=0000000000000000
00000000 00001010,这样就授权成功.
当变量yes=false时,为取消授权,先将temp取反,即为1111111111111111 11111111 11111011,现在只有要取消权限的位为0,其余全为1,然后与aclState求&运算,则除了要取消权限的位变0,其余的都不变,即aclState=0000000000000000
00000000 00001010.

授权流程



/**
	 * 授权:对角色或者用户
	 */
	public void addOrUpdatePermission(String principalType, int principalSn,
			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;
		}
		//如果不存在则创建新的实例
		if (acl==null) {
			
			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 tmp=1;
		tmp=tmp << permission;
		tmp &= aclState;
		if (tmp !=0) {
			return ACL_YES;
		}
		return ACL_NO;
		
	}




public boolean hasPermission(int userId, int resourceSn, int permission) {

		//查找对特定用户的授权
		ACL acl=findACL(ACL.TYPE_USER, userId,resourceSn);
		if (acl!=null) {
			int yesOrNo=acl.getPermission(permission);
		
			//如果是确定的授权
			if (yesOrNo != ACL.ACL_NEUTRAL) {
				return yesOrNo==ACL.ACL_YES ? true:false;
			}
		}
		//继续查找用户的角色授权
		String hql="select r.id from UsersRoles ur join ur.user u join ur.role r "+
					"where u.id=? order by ur.orderNo";
		
		List aclIds=getHibernateTemplate().find(hql,userId);
		//依照角色的优先级依次查找其授权
		for (Iterator iter = aclIds.iterator(); iter.hasNext();) {
			Integer rid = (Integer) iter.next();
			acl=findACL(ACL.TYPE_ROLE,rid, resourceSn);
			
			//一旦发现授权,即可返回结果
			if(acl!=null){
				return acl.getPermission(permission) == ACL.ACL_YES ?true:false;
			}
		}
		return false;
	}


上面是从了解权限到一个权限模块的解决思路和设计步骤,在大小不同的系统中可以适当的扩展和删减,这只是一种思路还有很多关于权限的解决方法比如RBAC等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: