4、权限隔离基础:权限模型概述、RBAC模型详解、ABAC模型详解

权限隔离这件事,说白了就是解决一个问题:谁,能对什么资源,做什么操作。

我早年做第一个企业级项目时,权限这块写得特别糙——直接在代码里写死 if (user.role === 'admin')。结果呢?上线第三天,产品经理就拿着新需求来找我:「我们要加一个超级运营角色,只能看订单不能改价格。」我一看代码,得,全得重构。从那以后,我再也不敢小看权限模型的设计了。

4.1 权限模型概述

权限模型,就是一套描述「主体-资源-操作」关系的规则框架。常见的模型有这么几种:

  • ACL(访问控制列表):直接给每个用户或每组用户挂资源权限列表。简单粗暴,但维护成本高。
  • RBAC(基于角色的访问控制):用户不直接关联权限,而是通过「角色」这个中间层来关联。这是目前最主流的方案。
  • ABAC(基于属性的访问控制):根据用户、资源、环境的多维属性动态计算权限。灵活,但实现复杂。
  • PBAC(基于策略的访问控制):把权限抽象成策略规则,通常与ABAC结合使用。

你想想看,ACL就像给每个员工单独发一把钥匙,人一多钥匙就乱套。RBAC则是按岗位发门禁卡——你是财务就给财务卡,你是运维就给运维卡。ABAC更高级,它不光看你是谁,还看你现在在哪儿、什么时间、用什么设备。

核心观点:没有最好的模型,只有最合适的模型。小型系统用RBAC足够,大型分布式系统往往需要RBAC+ABAC混合使用。

4.2 RBAC模型详解

RBAC(Role-Based Access Control)是1992年由David Ferraiolo和Richard Kuhn提出的。我接触的第一个权限框架Apache Shiro用的就是RBAC思想。说实话,这个模型能火三十年,不是没道理的。

4.2.1 RBAC的核心要素

要素 说明 举例
用户(User) 系统操作的主体 张三、李四
角色(Role) 权限的集合,用户与权限的桥梁 管理员、运营、审计
权限(Permission) 对资源的操作许可 创建订单、删除用户
会话(Session) 用户激活角色的过程 用户登录后选择角色

4.2.2 RBAC的三种模型变体

RBAC标准里其实分了几个层级。我习惯把它们理解成「基础版」「进阶版」和「完全版」。

  • RBAC0(基础模型):用户-角色-权限,最简单的三角关系。一个用户可以有多个角色,一个角色可以有多个权限。
  • RBAC1(角色继承模型):角色之间可以继承。比如「超级管理员」继承「普通管理员」的所有权限,再加一些高级权限。这能减少重复配置。
  • RBAC2(角色约束模型):增加了约束规则。比如「互斥角色」——一个人不能同时担任财务和审计;「基数约束」——一个角色最多只能有5个人。

我的经验:实际项目中,RBAC0就够用了。角色继承和约束虽然听起来很美好,但一旦业务复杂起来,角色层级深了,排查权限问题会非常痛苦。我曾经在一个项目里看到角色继承链长达7层,最后没人能说清楚某个权限到底是从哪一层继承来的。

4.2.3 RBAC的数据库设计

嗯,这里直接给出一套经典的五表设计。我几乎在每个项目里都用这个模板:

-- 用户表
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
);

-- 角色表
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
);

-- 权限表
CREATE TABLE `sys_permission` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `perm_code` varchar(100) NOT NULL,
  `perm_name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

-- 用户-角色关联表
CREATE TABLE `sys_user_role` (
  `user_id` bigint(20) NOT NULL,
  `role_id` bigint(20) NOT NULL,
  PRIMARY KEY (`user_id`, `role_id`)
);

-- 角色-权限关联表
CREATE TABLE `sys_role_permission` (
  `role_id` bigint(20) NOT NULL,
  `permission_id` bigint(20) NOT NULL,
  PRIMARY KEY (`role_id`, `permission_id`)
);

这套设计的核心思想就是「解耦」。用户和角色分开,角色和权限分开。哪天产品说「给运营加一个导出报表的权限」,你只需要在角色-权限表里加一条记录,完全不用动用户数据。

4.2.4 RBAC的优缺点

优点 缺点
模型简单,容易理解和实现 角色数量膨胀后管理困难
权限变更只需调整角色 细粒度控制不足(比如只能按部门限制)
符合企业组织架构直觉 无法处理动态条件(如时间、地点)
性能好,权限判断是O(1)级别 角色爆炸时维护成本急剧上升

4.3 ABAC模型详解

ABAC(Attribute-Based Access Control)是解决RBAC「不够灵活」这个痛点而生的。它不再依赖固定的角色,而是根据一组属性规则来动态判断权限。

举个例子:RBAC里,你给「运营」角色赋予了「查看订单」的权限。那所有运营都能看所有订单。但业务说:「运营只能看自己负责的区域的订单。」用RBAC怎么搞?要么给每个区域建一个角色(华东运营、华北运营……),要么在代码里硬编码判断。这两种方式,我都踩过坑。

ABAC的解法是:定义一条策略规则——用户.部门 == 订单.区域。谁满足这个条件,谁就能看。不需要建一堆角色。

4.3.1 ABAC的四类属性

  • 主体属性(Subject Attributes):用户的身份信息,如年龄、部门、职级、安全等级。
  • 资源属性(Resource Attributes):被访问对象的特征,如文档密级、创建者、所属项目。
  • 环境属性(Environment Attributes):访问发生时的上下文,如当前时间、IP地址、设备类型。
  • 操作属性(Action Attributes):要执行的操作类型,如读取、写入、删除、导出。

ABAC的核心公式:
权限 = 策略引擎(主体属性, 资源属性, 环境属性, 操作属性) → 允许/拒绝

4.3.2 ABAC的策略定义示例

假设我们有一个文档管理系统,需要实现这样的规则:「只有文档所属部门的员工,在工作时间(9:00-18:00)才能编辑该文档。」用ABAC的策略语言来表达:

{
  "effect": "允许",
  "条件": {
    "所有条件必须满足": [
      {
        "主体.部门": "等于",
        "资源.所属部门"
      },
      {
        "环境.当前时间": "在范围内",
        "值": ["09:00", "18:00"]
      },
      {
        "操作.类型": "等于",
        "值": "编辑"
      }
    ]
  }
}

你看,这里没有出现任何具体的用户名或角色名。规则是通用的,谁满足条件谁就能操作。这就是ABAC的魅力。

4.3.3 ABAC的实现架构

我参与过一个大型SaaS平台的权限重构,最终选型就是ABAC。它的架构大致分为三层:

  1. 策略管理点(PAP):负责定义和管理策略规则。通常是一个后台管理界面。
  2. 策略决策点(PDP):核心引擎,接收请求,根据策略计算是否允许。这是最复杂的部分。
  3. 策略执行点(PEP):拦截请求,调用PDP做决策,然后执行允许或拒绝。

下面这张图展示了ABAC的完整决策流程:

ABAC权限决策流程 用户发起请求 PEP(策略执行点) PDP(策略决策点) PAP(策略管理点) 属性源(LDAP/DB) 决策结果(允许/拒绝) PEP 执行结果 PDP 是核心决策引擎

4.3.4 ABAC的优缺点

优点 缺点
粒度极细,可以精确到单个资源实例 策略引擎性能开销大,复杂规则下延迟高
无需预定义角色,动态适应业务变化 策略管理复杂,非技术人员难以理解
支持多维条件组合(时间、地点、设备等) 调试困难,权限问题排查成本高
适合多租户、大规模分布式系统 需要专门的策略语言和引擎(如XACML、OPA)

避坑指南:我曾经在一个项目中过度使用ABAC,把几十条策略规则堆在一起。结果有一次线上排查一个用户为什么看不到某个报表,花了整整两天。最后发现是一条环境属性规则写错了——把「当前时间在09:00-18:00」写成了「当前时间在09:00-18:00之外」。所以我的建议是:能用RBAC解决的场景,不要硬上ABAC。ABAC适合那些权限规则频繁变化、条件复杂的场景。

4.4 RBAC vs ABAC:如何选择

很多团队在选型时会纠结。我一般会问三个问题:

  1. 你们的角色数量稳定吗?如果角色不超过20个,且很少变化,RBAC就够了。
  2. 权限判断需要依赖上下文吗?比如「只能在工作时间访问」「只能查看本部门数据」——有这类需求,考虑ABAC。
  3. 团队有精力维护策略引擎吗?ABAC需要引入OPA、Casbin这类框架,学习曲线不低。

实际项目中,我更推荐混合方案:用RBAC做粗粒度控制(比如「这个用户是运营角色」),用ABAC做细粒度过滤(比如「运营只能看华东区的订单」)。这样既保留了RBAC的简洁性,又获得了ABAC的灵活性。

我的习惯:先按RBAC把架子搭起来,等业务确实出现「角色爆炸」或「动态条件判断」的需求时,再在关键路径上引入ABAC策略。不要一开始就追求「完美」的权限模型——你永远猜不到产品经理下一步会提出什么需求。