权限系统设计中的基本概念,提供常用的权限设计思路

权限系统设计中的基本概念,提供常用的权限设计思路

本文的目的是帮助大家理清权限设计中的一些基本概念,提供通用的权限系统设计思路。

首先我们给出一个案例,让读者思考如果自己设计一个权限系统,如何满足这个需求。

需求描述:

在大学里,有很多人。 学生们即将参加期末考试。 对于某期末试卷,有以下权限管理要求:

注:考试过程分为考试前、考试中和考试后。 一个人可能有多个角色。

UML图:

角色权限图_角色权限设计5张表_角色和权限管理数据表设计

认证与授权

系统权限控制可以分为两部分:认证和授权。 两者是相对独立的概念,将它们分开有助于我们更好地理解权限系统的设计。

验证

所谓认证,就是判断你是否是你自己。 通俗地说,就是我们系统中常见的“登录”步骤。 这种验证的方法和技术有很多,比如表单验证、HTTP Basic验证、基于cookie的remember-me、OAuth2,甚至指纹验证等都可以。

本文不会详细讨论各种身份验证方法的技术细节,因为这部分不是本文的重点。 读者需要知道的是,权限控制的第一阶段是身份验证。 如果认证通过,则表示用户已经登录系统。 至于后续的各个业务的权限控制,则不会通过认证的方式进行管理。

授权授权

认证不关心业务权限控制,那么谁来控制呢? 这就是授权。 这就是本文的重点。

首先我们需要思考一个问题:我们系统的权限设计的大目标是什么? 我认为它既“灵活”又“易于管理”。 也就是说角色权限设计5张表,我们的权限设计应该能够灵活应对变化,包括用户的变化和业务权限需求的变化。 但同时又应该更容易管理,这样我们的权限才能足够清晰,不至于混乱。

那么基于以上目标,我认为权限系统的设计应该有以下三个原则:

刚刚够

这里强调的是,权限系统在满足需求的情况下应该尽可能简单,不应该过度设计。 比如我的个人博客网站,我只需要一个用户角色权限设计5张表,所以不需要做复杂的权限控制。

粒度适中

这里的“粒度”是指权限的粒度。 如果权限的粒度太粗,会导致一个权限在多个业务场景中使用,导致灵活性差; 而如果权限的粒度太细,又会导致权限过多,难以管理。

建议使用业务操作作为权限的粒度。 一项业务对应一项权限。 业界还有DDD(领域驱动设计)等工具来帮助更好地划分业务。

比如我们上面的案例,虽然老师和学生都有“写试卷”的操作创作人,但实际上,通过了解业务,我们可以将其分为“答题”和“评分”。

API和业务操作是否一一对应? 大多数业务场景应该是可以的,但也有例外。 例如,要发微信朋友圈,你需要添加某人,上传图片,并实际保存你要发送的内容。 这三个操作组成了“发朋友圈”的业务,对应了三个业务。

根据笔者的实践,比较推荐使用一个权限来访问这三个API。 或者三个权限,每个权限对应相应的API,但是有“权限组”的概念,将三个权限添加到一个权限组中,实际分配权限时分配这个权限组即可。 不建议只控制三个API,三个权限。

尽可能使用白名单

这是众所周知的安全原则之一。 我们在实现权限系统的时候,应该尽量使用白名单,而不是黑名单。 例如:只有具有xx权限的人才能进行xx业务。 而不是:没有xx权限的人可以进行xx业务。

主流权限设计模型

权限设计并不是一件容易的事,但是基本上所有的系统都需要权限设计。 事实上,业界已经有了一些主流的权限设计模式。 这里我们只简单介绍一些常用的。

前交叉韧带

访问控制列表多用于简单的权限控制。 尤其是在网络流量控制方面使用较多,在业务系统中使用较少。

RBAC

基于角色的访问控制(Role-Based Access Control),权限与角色相关联,用户通过分配合适的角色来获取这些角色的权限。 也是目前业界最主流的权限设计模式。 RBAC无法很好地检查与“数据状态”相关的权限,例如“只有老师可以在考试前查看试卷”的要求。 需要自己编写角色,然后在代码中编写逻辑检查。

阿巴克

基于属性的访问控制(Attribute-Based Access Control),为了解决上述问题,业界有一种解决方案,称为ABAC。 编写动态 DSL 来确定数据的状态,并使用一些自定义语法来控制权限。

ABAC 有时称为 PBAC(基于策略的访问控制)或 CBAC(基于声明的访问控制)。 ABAC通常用于平台级系统。 例如,AWS、阿里云等“云提供商”拥有海量的资源和角色,需要非常灵活的权限管理系统。

ABAC 的实施成本高昂。 管理也比较复杂。

示例(阿里云内存):

{
    "Version": "1",
    "Statement":
    [{
        "Effect": "Allow",
        "Action": ["oss:List*", "oss:Get*"],
        "Resource": ["acs:oss:*:*:samplebucket", "acs:oss:*:*:samplebucket/*"],
        "Condition":
        {
            "IpAddress":
            {
                "acs:SourceIp": "42.160.1.0"
            }
        }
    }]
}
复制代码

权限设计演变

基于上面提到的够用的原则,权限系统不应该过度设计。 我们可以按照权限要求从简单到复杂大致分为三类:

因为第二种适合大多数日常开发项目,所以后面主要讨论第二种。 如果是第三种,建议基于ABAC开发定制的权限系统。

区分访问和验证

我们先澄清一下这两个术语的一些概念:

很多第一次做权限设计的朋友往往会把两者混淆氛围,设计出来的权限可能看起来很混乱。

我们再分析一下这个案例。 以“读试卷”的业务操作为例,我们可以有一个名为READ_PAPER的Access,并将其分配给学生、教师、监考人员、教务主任、校长等角色。 这意味着他们可以调用这个业务API。 进入具体验证逻辑时,需要查询数据库检索试卷状态、对应班级、监考员ID等信息,并使用Validation验证数据是否可以被当前角色访问。

文章来源:https://zhuanlan.zhihu.com/p/106886281