一、RBAC基础
0. 前言
最近刚参与设计完角色权限的第二版,趁着还有些印象,赶紧来总结下,省的以后忘记了。
1. 什么是RBAC?
RBAC(Role-Based Access Control),基于角色的访问控制,就是用户通过角色与权限进行关联,通俗的说,就是一个用户有多个角色,每个角色又有多个权限,这样就构成了用户-角色-权限
的一种模型。在这种模型中,用户与角色之间,角色与权限之间,一般都是多对多的关系,而这种模型则就是最基础的RBAC的体现。
2. 什么是角色?
角色可以理解为一定数量的权限的集合,例如:一个论坛系统,“超级管理员”、“版主”都是角色,版主可管理版内的帖子、可管理版内的用户等。要给某个用户授予这些权限,当然可以直接将用户关联到具体的权限,不过更好的方式则是通过角色来关联用户与权限,比如将“版主”这个角色赋予某个用户。
3. 什么是权限?
所谓的权限一般可以分为三类:
- 菜单级别:也就是菜单的展示与隐藏;
- 页面元素级别:页面上某一个按钮,某一个div框的展示与隐藏;
- 数据级别:某一个url能否访问,某一个接口能否访问,同一个接口不同的人展示不同的结果;
其实权限的划分说简单也简单,说细也可以特别细,所谓的权限,无外乎用户看到与看不到,能操作与不能操作,大到某一个菜单,某一个页面,小到某一个按钮,某一个接口,都可以称之为权限。
二、RBAC应用
我们以一个例子来学习RBAC的具体应用。
1. RBAC0模型 - RBAC基础核心
某一天,你接手了一个需求,这个需求要求不同的用户登陆网站能看到不同的菜单。了解过RBAC的你很快就想到了通过角色来关联用户与菜单,于是你很快的就设计出了下面一套数据结构(图片来源:http://www.iteye.com/magazines/82):
在这种模型的数据模型设计中,涉及到了5张表:用户表,角色表,权限表,用户角色关联表,角色权限关联表。让角色作为中间人,来关联用户与权限,这样做很有好处:
不用用户直接关联菜单,降低耦合度,增加灵活性。如果你想让某几个人拥有相同的权限,只需要给他们配置相同的角色即可。
不过这时候你可能会意识到,由于菜单是多叉树结构,所以角色关联菜单的时候就会有两种关联方式:
- 关联整棵树,这样后台设置保存的时候就相对麻烦些,因为要考虑保存的是否是完整的树,并且保存的时候需要先删除再添加。但是展示的时候,直接取出来生成菜单树则就比较方便了;
- 关联树的叶子节点,那么设置的时候就会简单些,相对来说不会有那么多数据,但是展示的时候,再生成树就有点麻烦了,需要获取该节点的父节点,然后递归操作。
到底使用哪种方式呢,你还在考虑。不过无论哪种方式,都可以解决目前现有的问题,所以就这样,这套系统一直正常运行了好久,直到另一个需求的出现。
2. RBAC1模型 - 基于角色分层的模型
突然有一天,来了一个需求,要添加子账号登陆,拿一个商家管理系统来说,除了商家的账号登陆之外,商家想为每个员工各创建一个账号,然后员工登陆后操作该员工自己对应的权限。那这时候,上面这个权限模型就满足不了我们的需求了,这就引申出了角色的分层,而在实现上可以通过继承来实现。
这时候建表的时候就需要添加两张表:
- 子角色表,其中继承自父角色,继承关系的体现是通过保存父角色id来实现的;
- 子角色与子账号的关联关系表,就是保存相应的关联关系;
所谓的角色继承,和我们平时Java开发中的继承的概念类似,子角色的所有权限都来源于父角色,子角色有的父角色都有,父角色有的子角色不一定有。拿菜单来说,也就是子账号的菜单父账号必须存在,父账号有的菜单,子账号可以没有,而所谓的基础资源,也就是权限,则是共用一份。
角色分层的实现并非只通过继承,继承只是其中的一种方式,其实分层的本质就是细化角色,而实现的方式可以是各种各样,只需要围绕着这一本质即可。
3. RBAC2 + RBAC3
通常对RBAC的介绍还包括 RBAC2和 RBAC3这两种模型:RBAC2(角色限制模型),RBAC3(统一模型)。不过在实际工作中,并没有用到,本着实践才是检验真理的唯一标准的原则,没有用到就不多说了,等用到了,实践过了再来更新 (TODO)。
4. RBAC扩展1:用户组
我们以单纯的 用户-角色-权限
来说,我们指定权限,然后给用户分配角色,但是当用户的数量非常大时,要给系统每个用户逐个分配角色是件很繁琐的事情。这时,就可以对用户进行分组,每个用户组内有多个用户。
这样,除了给用户分配角色之外,还可以对用户组进行分配角色。最终,用户锁拥有的权限,就是用户个人拥有的权限与该用户所在用户组所拥有的权限的并集。
这样的话,在设计表的时候需要多三张表:
- 用户组对象表,保存用户组的一些简单的信息;
- 用户组与用户关联关系表,因为是多对多的关系,而如果一个用户只能属于一个用户组的话,那么这张表就可以省略,在用户表里添加用户组的id即可;
- 用户组与角色关联表,不多说了;
比如我们可以把一个部门当作一个用户组,如开发部,然后再给该部门直接赋予角色,这样这个部门的所有员工都拥有了该部门的权限。用户组的概念可以很方便的给多个用户赋予同样的权限,且不影响用户原本就拥有的角色权限。
5. 表的设计实现
前面说了这么多,这里来简单说下表的设计实现。在上文中,我们把权限分为菜单,页面元素,数据,所以建表的时候需要分别创建:
- 菜单表,菜单与角色关联表;
- 页面元素表,页面元素与角色关联表;
- 数据操作表,数据与角色关联表;
然后进行绑定的时候,需要将页面元素,数据操作,菜单一并绑定到角色上。
另外一种方式,权限类型统一,通过一张固定的权限表来关联角色,我们先来看下表结构:
- 菜单表,保存菜单信息;
- 页面元素表,保存页面元素信息;
- 数据操作表,保存数据操作相关信息;
- 权限表,保存上面三种绑定关系,全是一对一关系;
我们创建了三张基础表,然后创建一张权限表,然后权限表中添加两个字段:一个是菜单的id(其他同理),一个是权限类型,比如men
表示菜单的访问控制,element
表示页面元素的可见性控制,data
表示数据操作的权限;然后关联角色的时候,只需要关联这张表即可。
三、引申
1. ACL 模型
ACL(Access Control List),访问控制列表,是一种简单的将用户与权限直接关联的权限设计系统。ACL的设计,由于是用户直接绑定权限,所以获取展示的时候十分方便,不用做过多的查询。
另外,还有几种相关模型,了解即可:ABAC(基于属性的权限控制),PBAC(基于策咯的权限控制),GBAC(基于组的权限控制)等等。
2. 基于RBAC模型的框架或应用
目前最出名的恐怕是 Apache Shiro 框架了,其次 Spring Security也是Spring提供的用于权限控制的框架。