权限控制是一个古老的话题,你可能会想有没有什么权限设计方案可以满足所有的应用场景呢?
答案是没有,就像几乎所有问题一样,没有一种系统可以解决所有情况的,我们需要根据不同的场景和需求来设计不同的系统。
权限控制主要设计用户
、角色
、组
、对象
、操作
、权限
等对象。下面我先对这些对象做些解释,让大家先有个概念。然后我们再说说业界有哪些比较优秀的权限控制设计方案。
发起操作的主体。
对于用户的抽象概念,类似于用户的属性,比如管理员
就是一个角色。
可以是用户组,也可以是角色组,也可以是对象组。
指操作所针对的客体对象,比如订单数据或图片文件。
指作用于对象的动作,比如读取、写入。
一般把对象和操作的对应关系和在一起叫权限,比如读取文件的权限,读取就是操作,文件就是对象。
即自主访问控制
,英文全称是Discretionary Access Control
。
系统会识别用户,然后根据被操作对象(Subject)的权限控制列表(ACL: Access Control List)或者权限控制矩阵(ACL: Access Control Matrix)的信息来决定用户的是否能对其进行哪些操作,例如读取或修改。
而拥有对象权限的用户,又可以将该对象的权限分配给其他用户,所以称之为“自主(Discretionary)”控制。
这种设计最常见的应用就是文件系统的权限设计,如微软的NTFS。
DAC最大缺陷就是对权限控制比较分散,不便于管理,比如无法简单地将一组文件设置统一的权限开放给指定的一群用户。
即强制访问控制,英文全称是Mandatory Access Control
。
MAC是为了弥补DAC权限控制过于分散的问题而诞生的。在MAC的设计中,每一个对象都都有一些权限标识,每个用户同样也会有一些权限标识,而用户能否对该对象进行操作取决于双方的权限标识的关系,这个限制判断通常是由系统硬性限制的。比如在影视作品中我们经常能看到特工在查询机密文件时,屏幕提示需要“无法访问,需要一级安全许可”,这个例子中,文件上就有“一级安全许可”的权限标识,而用户并不具有。
MAC非常适合机密机构或者其他等级观念强烈的行业,但对于类似商业服务系统,则因为不够灵活而不能适用。
即基于属性的访问控制,英文全称是Attribute-Based Access Control
。
ABAC被一些人称为是权限系统设计的未来。
不同于常见的将用户通过某种方式关联到权限的方式,ABAC则是通过动态计算一个或一组属性来是否满足某种条件来进行授权判断(可以编写简单的逻辑)。属性通常来说分为四类:用户属性(如用户年龄),环境属性(如当前时间),操作属性(如读取)和对象属性(如一篇文章,又称资源属性),所以理论上能够实现非常灵活的权限控制,几乎能满足所有类型的需求。
例如规则:“允许所有班主任在上课时间自由进出校门”这条规则,其中,“班主任”是用户的角色属性,“上课时间”是环境属性,“进出”是操作属性,而“校门”就是对象属性了。为了实现便捷的规则设置和规则判断执行,ABAC通常有配置文件(XML、YAML等)或DSL配合规则解析引擎使用。
总结一下,ABAC有如下特点:
集中化管理
可以按需实现不同颗粒度的权限控制
不需要预定义判断逻辑,减轻了权限系统的维护成本,特别是在需求经常变化的系统中
定义权限时,不能直观看出用户和对象间的关系
规则如果稍微复杂一点,或者设计混乱,会给管理者维护和追查带来麻烦
权限判断需要实时执行,规则过多会导致性能问题
既然ABAC这么好,那最流行的为什么还是RBAC呢?
我认为主要还是因为大部分系统对权限控制并没有过多的需求,而且ABAC的管理相对来说太复杂了。Kubernetes
便因为ABAC太难用,在1.8
版本里引入了RBAC的方案。
即基于角色的访问控制,英文全称是Role-Based Access Control
。
因为DAC和MAC的诸多限制,于是诞生了RBAC,并且成为了迄今为止最为普及的权限设计模型。
RBAC在用户和权限之间引入了角色
的概念。
每个用户关联一个或多个角色,每个角色关联一个或多个权限,从而可以实现了非常灵活的权限管理。角色可以根据实际业务需求灵活创建,这样就省去了每新增一个用户就要关联一遍所有权限的麻烦。
由RBAC还可以做些扩展,比如下面两种方式。
即Hierarchical Role,顾名思义,角色继承就是指角色可以继承于其他角色,在拥有其他角色权限的同时,自己还可以关联额外的权限。这种设计可以给角色分组和分层,一定程度简化了权限管理工作。
即Separation of Duty,为了避免用户拥有过多权限而产生利益冲突,例如一个篮球运动员同时拥有裁判的权限(看一眼就给你判犯规狠不狠?),另一种职责分离扩展版的RBAC被提出。
如图所示,每个用户关联一个或多个角色,每个角色关联一个或多个权限。权限是由一对对象和操作组成。
由此我们可以设计出主要的表结构关系。
userid | roleid |
---|---|
10001 | 20001 |
roleid | permissionid |
---|---|
20001 | 50001 |
permissionid | objecteid | operationid |
---|---|---|
50001 | 30001 | 40001 |
有了上面三张表,我们就有了完整的映射关系,还有些表是定义各个对象的,比如,
username | telephone | status | |
---|---|---|---|
zhangsan | [email protected] | 13411111111 | enabled |
roleid | rolename | rolecname |
---|---|---|
20001 | developer | 业务开发 |
operationid | name | describe |
---|---|---|
40001 | Query | 查询 |
objectid | name | type | desc |
---|---|---|---|
30001 | www.test.com | 域名 | test |
API网关的权限控制,我们采用RBAC模型。
API网关里面的对象其实只有两种,一种是前端元素,比如菜单、按钮;另一种是API接口,比如某个微服务的查询域名接口。
对于前端元素,操作对象只有在页面上显示或者不显示;而对于API接口,操作对象只有能调用或者不能调用。
根据上面的分析,操作对象其实就可以省略了,那么我们的RBAC模型就更简单了。可以简化为下图,