权限设计总结
权限设计是在系统中非常重要的一个模块设计,所处位置十分关键,如果在系统中权限设计不是很理想,会导致整个系统设计宏观上的缺陷,不能满足业务领域的需求变化。如何设计一个比较通用的权限管理模块,如何能满足大多数业务领域的权限需要,这并非易事,前些日子看了一下资料,特总结一下。
权限设计的实质其实就是对三元表进行建模,所谓的三元在系统当中则是用户、角色、以及资源,用户与角色很容易理解,而资源是什么呢,也很简单,资源就是系统模块。不同的业务需求有不同的权限设计,但是通常来说都是建立在这三个基础元素之上的,所以让我们来看2个比较典型的建模方式:
一、RBAC(role-based access control),基于角色的访问控制,顾名思意,在整个权限的管理过程当中,角色是一个根本,从角色出发来进行权限的授权和认证
从RBAC这个基于角色的权限设计,我们可以看到其中有几点需要仔细去思考的地方:
?
1 、用户和角色之间的关系是多对多,权限和角色也是多对多,那么这里权限是什么呢,这里的权限包括了2个部分,第一个是资源,第二个是操作,资源是系统模块,而操作是某个模块里面具体的用户行为,通常来说就是CRUD,资源和操作之间本来也是有关系的,这里先忽略点,把他们都看成一个整体,纳入到我们的RBAC中。
2、角色表里面有个自连接,很明显。也就是角色之间有父子集成关系,某一个角色是另外一个角色的上级,通常在业务领域当中表现为:项目总监 -> 产品经理 项目总监 -> 项目经理 这样的结构必须有一个自身的关联关系。
3、什么是约束,约束就是用户与角色之间的一个限制条件,比如一个用户有多个角色,每个角色自己也对应自己的权限,也就是用户拥有很多互斥的权限,如何区分这些互斥权限,就需要约束来进行控制,从这个约束来看实际我们就可以发现一个很重要的概念,优先级,之后在另外一个权限设计当中会提到,约束不只这一种,还有很多其他的约束,比如,某一个用户在某一个时间内不能拥有哪些角色,这个是根据时间来进行约束,所以有很多很多的约束,来关联限制用户与角色。
4、什么是会话,会话在RBAC中也是一个很重要的概念,具体是什么呢,意思就是一个用户,在某一个会话过程当中只能拥有0个或者多个角色,何谓会话过程,会话过程其实很抽象,可以表现为某一个时段,例如用户登入系统之后拥有管理者角色,当用户链接到后台管理系统的时候,这个时候角色发生了改变,登陆用户变成了系统员身份,我们可以分别把这2个时段过程看为2个会话,这样就很容易理解了。
RBAC呢,有一个缺陷,也是它半身的一个特点,所有权限管理要从角色出发,这个限制了他在很多业务领域得不到很好的应用,很多业务领域提出的需求很可能会存在角色拥有权限,用户本身也存在着权限,不仅可以按照角色来进行授权认证,还能够靠用户自身来进行授权认证,那么这个时候,RBAC肯定也就不适合了,另外,我认为,RBAC里面的概念不是很容易运用到系统当中,看起比较复杂,在大多数的情况下,我们也就没有选用这种方式来构建我们的权限模块。
?
二、比较传统的但是适合很多种业务领域权限设计方案:
这个传统的权限设计跟RBAC有着明显的区别,先来看看这些classModel的意思,User,Role,UserRoles这个地方我们其实可以看成是User和Role的多对多关系的分解,建立了一个新classModel,形成2个一对多的关系,为什么要分解这个关系呢,因为我们有一个优先级的问题存在,也就是说一个用户拥有多个角色,这些角色拥有不同的权限,必然会存在互斥的权限,那么一旦互斥,我们该以哪一个为标准呢,所以就要引入优先级,在互斥情况下,优先级高的角色权限为主权限,之后我们就要以主权限为主。Module是系统的模块,模块与模块之间其实也有个自关联的关系,因为常常在系统当中也存在着一级菜单,二级菜单这样的设定,Permission是权限,这里面其实只有4种对象,就是CRUD。最重要的东西是ACL,什么是ACL,即access control list,访问控制列表,这个类直接把最重要最核心的关联表现了出来。
1、ACL使得角色、用户与Module产生了联系,使得角色,用户都具有自己相应的权限,这就提供了RBAC不能提供的功能。
2、ACL里面有几个属性,一一介绍一下,主体标识,什么是主体呢,其实这里主体就2个,一个用户,一个角色,所谓标识,就是标识这2个主体的。主体ID,就是分别对应角色和用户的ID。资源标识就是module的ID。授权状态其实就是是否拥有权限,可以用0或1来代表。是否有继承角色的权限,如果有的话那么就算用户自身有权限,也不管用,所拥有的权限也是角色权限,如果不继承的话,那么如果用户自身有权限,就以自身的权限为主。这里可能有很多人会疑惑,就是为什么在面向对象的系统当中设定了外键ID,而不是聚合进来一个对象,我认为在这里2种方式都是可以的,不想聚合进来对象是因为在加载ACL的时候只想考虑ACL的读取,不想加载其他不相关的对象,我可以加载好ACL之后再去加载相应关联对象,因为ACL说白了就是一个中间表,因为关系很多,不想一下子就加载很多的东西进来,这会导致效率上出现问题,所以在ORM的关联映射上就放弃了对象的关联映射,这里并不是放弃面向对象。当然如果是对象映射也是可以的,因为这里数据量并不大,也都是两两产生关系,很适合用hibernate本身的东西来解决,如果关系分散更多的话,还是应该自行SQL解决。授权状态这个很特殊,从数据类型来看,它是一个int型的,但是在做处理的时候,会把他看成一个32位的二进制数字,我们取后4位来对应CRUD这些操作做对应的权限,这个是我从一个资料上看来的,觉得这种方法很不错,简单,方便,易于使用。比如0为C,1为R,2为U,3为D,每一位上0和1代表是否有权限,这样就完成了操作上的数据授权。Permission很简单,上面也说了就是CRUD4种对象,它跟ACL之间的关系是多对1的关系,代表了一个ACL到底拥有CRUD的哪几项。
通过这个传统的权限设计,我们可以很容易的看清楚,很方便的控制一件事情,那就是:比较细粒度的控制了哪一个用户对哪一个资源的哪一个操作具有权限。我们非常方便的做到了这一点了,那权限设计还夫复何求呢。
?