权限系统通用的设计模型

权限系统通用的设计模型

10月 29, 2020
系统设计

权限系统是一个比较通用的系统,几乎所有的后台业务都会涉及到,关于权限系统的设计经过一些最佳实践也已经被总结成各种模型,比如 ACL、RBAC、ABAC、PBAC等,下面开始详细介绍。

基本概念 #

在很多权限系统的框架和服务,包括 CasbinAuthing 里面,都有下面这些名词作为基础,所以在开始之前,还要先理解这些概念。

主体(Subject) #

想要访问资源的主体,可以先理解为用户。

对象(Object) #

用户要访问(或更改)的资源。

动作(Action) #

用户对资源执行的操作,比如文件的读写,数据是否能访问、操作。

ACL #

权限控制表简称 ACL(Access-Control List),ACL 记录了哪些资源可以被哪些主体进行哪些操作,是一个关系表,大部分的权限系统里都会有这张表。而在一个 ACL 表里,一般会有主体、对象和动作三个要素,设计出来的库表一般为:

idsubjectobjectaction
1user1文档 1查看
2user1文档 2编辑
3user2文档 2删除

DAC #

自主访问控制简称 DAC(Discretionary Access Control),DAC 是 ACL 的一种实现,里面的主体就是用户。这样的设计简单直接,查询效率很高,强调自主是因为 DAC 模型将授权的权利下放,允许拥有指定权限的用户可以自主地将权限授予给其他用户。比如,在纯粹 ACL 模型下,每次新人培训,人事总监都要通知 IT 部,将培训文档的访问权限授予新人。在 DAC 模型下,人事总监只需将文档的访问权限授予人事专员。之后,每次新人培训,由人事专员将文档的访问权限授予不同的新人。

DAC 的缺点也很明显,比如在一家公司,每有一个新人入职,就需要人事专员给新人添加各种系统的权限,这些工作的重复性很大,而且文档越多,工作量越大。

MAC #

强制访问控制简称 MAC(Mandatory Access Control),是为了弥补 DAC 权限控制过于分散的问题而诞生的,在 MAC 模型中,会对资源进行类别划分、对主体进行等级划分。在进行权限校验时,会同时对主体的等级和资源的类别进行匹配,实现资源与主体的双重验证,确保资源的交叉隔离,提高安全性。比如情报局的任务有秘密级、机密级、绝密级,角色有007、M 和 Q,MAC 非常适合机密机构或者其他等级观念强烈的行业,但对于类似商业服务系统,则因为不够灵活而不能适用。

MAC的权限库表设计可能为:

资源配置表
  资源: 财务文档
    主体: 财务人员
    等级:经理级
    操作:查看

主体配置表
	主体: 李女士
  	类别: 财务人员
  	等级:经理级

RBAC #

基于角色的访问控制简称 RBAC(Role-Based Access Control)。在 RBAC 里面,一个人有了一些固定的权限后,他就是一个角色,于是引入了“角色”的概念,可以理解为角色就是一组权限的集合。这个模型有效的解决了 ACL 模型里面管理员给每一个新人逐个系统加权限的问题,只需要在最初配置好角色所拥有的权限,在新人入职时给新人分配一个角色就可以了,大大减少重复性操作负担。需要注意的是,实现时要验证角色是否有某个权限,而不是去验证用户是否是某个角色。

引入角色概念后,RBAC 演进出了 4 种细分模型:RBAC0、RBAC1、RBAC2、RBAC3。

RBAC0 #

RBAC0 就是上面说的最基础的 RBAC 模型,只引入了角色的概念,在这个模型下,用户和角色是多对多的关系,角色和权限之间也是多对多的关系,角色实现了用户和权限间的解耦:

用户 <=关系表=> 角色 <=关系表=> 权限

RBAC1 #

RBAC1 模型是 RBAC0 的升级版,它对角色这层元素上进行了细分,引入角色继承的概念,也就是可以继承某个基础角色生成子角色。RBAC1 模型可以更好地在角色层面进行细分,更好地映射了企业组织架构中的职能的权限,根据实际的管理权限对相似职能的角色进行删减以达到级别分明的效果。

应用场景:市场经理岗位可能会分为总监级别、经理级别、副经理级别,这时候如果小陈只是一个副经理级别的,那么他所拥有的市场经理的权限肯定就没有总监级别的多1

RBAC2 #

在 RBAC2 中对角色层面增加了职责分离的限制:

(1)静态职责分离(Static Separation of Duty))

  • 角色互斥:相同用户不能同时拥有互斥关系的角色,例如会计和出纳两个角色就是互斥的
  • 基数约束:角色被分配到的用户有数量上限,例如公司中只有一个 CEO 职位,那么这个角色的数量就是有限的
  • 先决条件角色:要拥有更高级别的角色权限,需要先获取到相对来说低级别的一些权限,例如副经理要想获取到总监级别权限,那么他需要先获取到经理级别的权限。

(2)动态职责分离(Dynamic Separation of Duty)

用户在一次会话(Session)中不能同时激活自身所拥有的、互相有冲突的角色,只能选择其一。

RBAC3 #

RBAC3 模型就是 RBAC1 + RBAC2 两个模型的合集,所以 RBAC3 既有 RBAC1 的角色等级划分,也有 RBAC2 的角色限制。这种模型只有在系统比较复杂的时候才派得上用场,不然设计得过度复杂,对开发和后期维护也不是好事情。

RBAC 的优缺点 #

RBAC 的优点很明显就是只需要分配一次角色,大大减少了重复性操作负担,解耦了用户和权限的关系。

但是 RBAC 并不总能满足所有权限的场景。比如,我们无法对销售角色进行个体定制。比如,销售角色拥有创建、删除的权限。如果我们要对销售小李,去掉删除的权限。那么,我们就必须创建另一个角色,来满足需求。如果这种情况很频繁,就会丧失角色的统一性,降低系统的可维护性。

用户组 #

很多情况下权限系统还会在用户<-->角色<-->权限的基础上引入用户组的概念,用户组就是用户(主体)的集合,打个比方,在一家公司需要将岗位 A 的所有人都调配到岗位 B,如果单纯的更改用户的角色,操作量还是很大,加入用户组的概念后,只需要将一个用户组的角色从岗位 A 改为岗位 B 就可以了。

用户<=关系表=>用户组<=关系表=>角色<=关系表=>权限

角色和组的区别 #

角色和组两个概念可能会让人混淆,这里做个区分:

  • 主体可以是用户,也可以是组,角色赋予的是主体。
  • 角色是权限的集合。
  • 组是用户的集合

ABAC #

基于属性的访问控制(Attribute-Based Access Control,简称 ABAC)是一种非常灵活的授权模型,不同于 RBAC,在 ABAC 中,一个操作是否被允许是基于对象、资源、操作和环境信息共同动态计算决定的2

  • 对象:对象是当前请求访问资源的用户。用户的属性包括ID,个人资源,角色,部门和组织成员身份等;
  • 资源:资源是当前访问用户要访问的资产或对象(例如文件,数据,服务器,甚至API)。资源属性包含文件的创建日期,文件所有者,文件名和类型以及数据敏感性等等;
  • 操作:操作是用户试图对资源进行的操作。常见的操作包括“读取”,“写入”,“编辑”,“复制”和“删除”;
  • 环境:环境是每个访问请求的上下文。环境属性包含访问尝试的时间和位置,对象的设备,通信协议和加密强度等。

如何使用属性进行动态计算 #

在 ABAC 的决策语句的执行过程中,决策引擎会根据定义好的决策语句,结合对象、资源、操作、环境等因素动态计算出决策结果。每当发生访问请求时,ABAC 决策系统都会分析属性值是否与已建立的策略匹配。如果有匹配的策略,访问请求就会被通过。

例如,策略「当一个文档的所属部门跟用户的部门相同时,用户可以访问这个文档」会被以下属性匹配:

  • 对象(用户)的部门 = 资源的所属部门;
  • 资源 = “文档”;
  • 操作 = “访问”;

策略「早上九点前禁止 A 部门的人访问B系统;」会被以下属性匹配:

  • 对象的部门 = A 部门;
  • 资源 = “B 系统”;
  • 操作 = “访问”;
  • 环境 = “时间是早上 9 点”。

浓缩到一句话,在 ABAC 模型下你可以细粒度地授权在何种情况下对某个资源具备某个特定的权限。

优缺点 #

基于了这些属性,就可以进行规则的定制,可见灵活但是复杂,配置的工作量根据实际业务的复杂度成正比。kubernetes 也因为其过于复杂改用了 RBAC3

ABAC, Attribute Based Access Control, is a powerful concept. However, as implemented in Kubernetes, ABAC is difficult to manage and understand. It requires ssh and root filesystem access on the master VM of the cluster to make authorization policy changes. For permission changes to take effect the cluster API server must be restarted.

RBAC 也相应解决了使用 ABAC 时面临的问题:

RBAC permission policies are configured using kubectl or the Kubernetes API directly. Users can be authorized to make authorization policy changes using RBAC itself, making it possible to delegate resource management without giving away ssh access to the cluster master. RBAC policies map easily to the resources and operations used in the Kubernetes API.

除了维护难度高以外,ABAC 的规则判断是实时执行,规则过多或者需求复杂时需要关注性能问题。

选择 RBAC 还是 ABAC #

在这里,组织的规模是至关重要的因素。由于 ABAC 最初的设计和实施困难,对于小型企业而言,考虑起来可能太复杂了。

对于中小型企业,RBAC 是 ABAC 的简单替代方案。每个用户都有一个唯一的角色,并具有相应的权限和限制。当用户转移到新角色时,其权限将更改为新职位的权限。这意味着,在明确定义角色的层次结构中,可以轻松管理少量内部和外部用户。

但是,当必须手动建立新角色时,对于大型组织而言,效率不高。一旦定义了属性和规则,当用户和利益相关者众多时,ABAC 的策略就更容易应用,同时还降低了安全风险。

简而言之,如果满足以下条件,请选择 ABAC:

  • 你在一个拥有许多用户的大型组织中;
  • 你需要深入的特定访问控制功能;
  • 你有时间投资远距离的模型;
  • 你需要确保隐私和安全合规;

但是,如果满足以下条件,请考虑 RBAC:

  • 你所在的是中小型企业;
  • 你的访问控制策略广泛;
  • 你的外部用户很少,并且你的组织角色得到了明确定义。

PBAC #

PBAC(Policy-Based Access Control)是基于策略的权限控制,其实 ABAC 里已经开始有策略的味道了,PBAC 就是相对于传统的 ABAC 更加强调策略(Policy),故 PBAC 也是 ABAC。参考维基百科 XACML 里的描述4

XACML is primarily an attribute-based access control system (ABAC), also known as a policy-based access control (PBAC) system, where attributes (bits of data) associated with a user or action or resource are inputs into the decision of whether a given user may access a given resource in a particular way.

框架实现 #

Casbin #

Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。上述的权限模型,都可以通过 Casbin 来实现,非常好上手,文档提供了工作原理5的介绍,可以进行详细了解。

不过注意,Casbin 没有以下功能:

  1. 身份认证 authentication(即验证用户的用户名和密码),Casbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 Casbin 进行访问控制,二者是相互配合的关系。
  2. 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储 RBAC 方案中用户和角色之间的映射关系。

Shiro #

Apache Shiro 是一个强大而灵活的开源安全框架,可以干净地处理身份验证、授权、企业会话管理和加密,是 Java 技术栈,感兴趣可以了解下。

Spring Security #

Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,也是 Java 技术栈,感兴趣可以了解下。

Django #

Django 是一个 Web 框架,因为以前用过 Django 比较了解,顺便说一下,Django 自带的基础功能也实现了一层针对 Model 层数据的 RBAC,可以在此基础上做一些业务开发。另外我也在其 Admin 的基础上做了一个针对 API 的权限校验,感兴趣可以看下:django-api-permission

总结 #

不过 Shiro 和 Spring Security 甚至 Django 都不支持 ABAC 模型,需要另外开发业务逻辑,Casbin 可以通过模型配置文件的方式原生支持,且常用语言都提供了 SDK。

本文共 4413 字,上次修改于 Jul 9, 2024,以 CC 署名-非商业性使用-禁止演绎 4.0 国际 协议进行许可。

相关文章

» 了解下 Protobuf 相关概念

» Kafka 和 RabbitMQ 对比

» Redis 的分布式锁使用注意

» Redis 实现布隆过滤器

» 说说实际工作中 GraphQL 的使用体验