RBAC权限系统设计之我见

同一类主题的另一篇博客请移步:权限设计简要概括 

   这两天在做公司开放平台项目的权限系统方面的设计。下面就谈谈我对权限系统设计的一些看法(部分概念说明参考了网上资料),欢迎大家一起交流。

    提到权限系统,做过OA系统的开发者都会想到RBAC(Role Based Access Control,基于角色的权限控制)。RBAC中至少包含三类基本角色:

  • User,即用户,比如张三、李四等

  • Role,即角色,比如经理、副经理、普通职员等

  • Permission,即权限,权限一般和实际可执行的操作或者菜单选项直接一一映射,比如操作打印机、审批请假单等,权限直接操作的对象就是资源(比如在开放平台中API接口是一种资源)            

    上面用户和角色是多对多关系,角色和权限也是多对多关系,查询某个用户是否具有某个权限时,先查找用户有哪几个角色属性,然后根据角色属性再去获取权限,即顺序决定关系

    示意图如下(注意各个实体之间的映射关系为了简便没有画出来):

193654_QWsK_111708.png

    上面是最简单的RBAC模型,对于用户数较少的情况它能很好地解决问题,但一旦用户规模增大,它的弊端就出来了,这时候新增一种角色就需要为那么多的用户逐个授予角色,于是我们又引入了用户组的概念,用户可以属于某个用户组(注意是可属于,不是一定要属于),这时候某个用户的权限=他之前根据角色获得的权限 U 他所属用户组的权限,U表示取并集,如下:

194829_3R0y_111708.png

    当然还可以增加其他与用户组类似的东西,比如测试组,也为它分配权限,然后用户也可以属于某个测试组。

    同理,当权限数目增加到一定规模的时候,也不适合一一为每个角色分配权限,这时候我们可以引入权限组,一个权限组包含多个权限,权限组可以分配给角色,角色的权限=他上面获得的权限 U 为他分配的权限组内的所有权限,如下:

194941_rncn_111708.png

    当然上面是严格的自上到下层次结构,不能穿透,有时候一些复杂场景是允许穿透的,即直接给用户、用户组分配权限或权限组,如下:

195242_x16Z_111708.png

    这样虽然增强了灵活性,却带来了比较多的复杂性,一般我们做到第二幅或者第三幅图的地步就差不多了。另外有人可能会问是否有必要也弄一个角色组的东西?因为系统中的角色数目一般不会太多,所以没必要分出角色组。

    下面来看一个实例,在开放平台项目的权限系统设计,我采用了下面这样的方案(省略了部分字段,不涉及公司机密信息):

195922_dIZ4_111708.png

    整体来说也是基于RBAC模型,也有用户(这里是开发者)、角色、权限、权限组等概念,我这里为了避免不必要的复杂性,严格要求从上到下各层之间不能穿透。除此之外有两个地方值得提下。

    第一,我为每个权限app_permission都设置了一个weight字段,即权值,这个值是2^0,2^1....这种顺序递增的值,而app_permissioni_group也有一个weight字段,这个字段的值是由权限组所包含的所有权限的weight值进行或运算得到的,这样我不必在内存中维护权限与权限组的映射关系,可以分开维护权限和权限组配置信息。这样内存中维护的配置信息大概有:权限列表权限分组列表用户 <=> 权限分组映射。(为什么不直接维护用户 <=> 权限映射,因为用户基数一般很大,权限数也可能有几百个,这样太费内存了,为每个用户的权限列表维护一个BitMap依然很耗内存。而权限分组比较少,所以就可以在内存中维护用户到权限分组的映射关系,当然也可以用BitMap)

    当用户请求某个资源,比如/albums/123/comments(即专辑123的所有评论),我们先根据这个资源找到对应的权限(一一对应关系),然后遍历该用户的权限分组,并用每个分组的weight值与这个权限的weight值进行与运算,如果得到的结果是0,则表明该用户没有该资源的权限,反之非0则表示有该资源的权限。

    第二,我增加了一张开发者特殊权限表app_user_privilege_permisssion,这又是为何?暂时先遮住这张表想想设计有什么问题。很明显所有具有相同角色的开发者都具备完全相同的权限列表。这样带来的一个好处是:对于用户,他不需要进行复杂的权限选择,只需要申请某个角色等级,然后他自动拥有了该角色等级拥有的所有权限。但有时候这样会显得呆板,因为某些情况某些开发者可能会需要一些特殊权限,而这些特殊权限通过角色 => 权限组 => 权限的顺序关系并不能获得。所以我特地引入app_user_privilege_permission特权表,它实际上也做了一次跨层穿透。当然你可能反问如果需要特殊权限,那么可以增加一种特殊角色、一种特殊权限分组,然后把这种特殊权限赋给特殊权限分组,特殊权限分组再赋给特殊角色。这样做显然是不合理的,因为开发者需要的特殊权限五花八门,如果有更多的特殊权限需求,那么会增加多少角色和权限分组呢?

    此外,特权表也能很方便地进行权限回收,并且还带来了一种意料之外的功能,那就是假如我要增加一种实验性权限,但又不打算为这个权限归到已有的权限分组或者为它建新的权限分组,因为它只是一种实验性的权限。我也只想把这项实验性权限开放给少量用户,比如一千个用户,那么我直接在特权表中增加配置就好了。

    但演化到上面这种设计方案之前,也想到了两种稍显简单的设计方案:

  • 没有权限组和角色概念,只留下用户和权限:用户有一个等级属性(INT类型),权限也有一个等级属性(INT;类型),如果某个权限的等级值小于用户的等级值,那么该用户就具有该权限。这种方案主要看业务需求,看业务上是否允许单纯地根据等级值来进行授权

  • 在上面这种方案的基础之上,去除用户的等级属性,也去除权限的等级属性,直接维护用户和权限的多对多映射关系。这下审核人员就麻烦了,原因你懂的   

    另外我看了下MySQL的权限设计,这里也稍微提下。MySQL主要通过USER_PRIVILEGES、DATABASE_PRIVILEGES、TABLE_PRIVILEGES、COLUMN_PRIVILEGES这几张表来控制用户是否有权限访问库、表和列。先从USER_PRIVILEGES中查找用户是否有某个数据库操作(比如SELECT、UPDATE)的权限,如果是那么该用户就具有对所有库的所有表的所有列的该种操作权限。如果不是则继续从DATABASE_PRIVILEGES表查找用户是有有对某个库的某个操作的权限,如果是则用户拥有对该库的所有表的所有列的该种操作权限。以此类推。

    文章原创,转载请注明出处:http://my.oschina.net/feichexia/blog/289532,谢谢!

转载于:https://my.oschina.net/feichexia/blog/289532

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值