分权分域设计

cover
总结对分权分域的理解和方案设计

第一次实现RBAC的权限管理系统,已经是十几年前的事了。但至今,我还是无法确定“分权分域”,是一个词还是两个词,说的是一件事还是两件事。尝试google了一下,也没有找到确切的答案。本文记录一下个人的理解。

概念

我在网上看到以下说法,

分权分域,是权限管理系统所能实现的效果之一,简单来说就是两点:
分权,定制用户权限,不同的用户登录系统后的界面不同,所能进行的操作也不同。
分域,控制用户权限,防止越权访问和跨域访问。

按这种说法,“分权分域”说的就是一件事,分权是定义权限,分域是分配权限。我在网上没有找到标准的概念。

我个人的理解,是把“分权”和“分域”看作2件不同的事情。分权解决“用户能操作什么资源”的问题,分域解决“在有权限的前提下,用户能看到哪些数据”的问题。我不确定这种理解对不对,下文都以这种理解为基础。

分权设计

分权的设计,基本上参考RBAC就很完善。简而言之,大致是以下几个思路

  1. 每个“资源”都有ID,比如菜单项、页面、API、数据库表都是资源,跟“权限”一一对应
  2. 用户有N个权限,当用户请求资源时,检查用户是否有相应的权限,如果没有就拒绝请求
  3. 为了方便给用户授权,引入“角色”的概念,避免重复操作

E-R图

ER

控制点

有了资源和对应的权限模型之后,需要针对不同的资源类型,在加载的入口增加权限控制的逻辑

通常来说,常见的资源类型有:

  1. 菜单,决定是否展示某个菜单项
  2. 页面,表现为URL,决定用户是否可以访问某个页面
  3. API,后端接口是否允许调用
  4. 数据库表,某张表是否可以访问。可以细化为针对CRUD设置不同的权限

以API类型的资源为例,在调用API的入口,检查用户的权限,如果没有权限则拒绝调用。其他的控制点都类似,不赘述

要点是,创建权限时,通常需要设置一个KEY_CODE,或者符合某种命名规则。因为控制点的校验代码需要有某种规则来匹配权限

如果用KEY_CODE,控制逻辑类似于:

1
2
3
4
5
6
7
8
9
10
String GET_BALANCE_API = "get_balance_api";// 权限的标识

String userId;
List<Perm> permList = resolvePerms(userId);// 获取当前用户权限列表

if(!permList.contains(GET_BALANCE_API)){// 权限里不包含当前请求API,则拒绝请求
return;
}

// 业务逻辑代码

可以发现,这样比较麻烦,因为在每个API的入口,都需要检查KEY_CODE是否符合。如果设计一个命名规则,在创建资源和权限时,都遵循这个命名规则,那么就可以写通用的校验逻辑

权限分配

资源和权限配置完成以后,需要分配给用户。由于用户很多,批量处理会很困难,所以引入角色的模型。这也是RBAC的精髓之一

授权操作通常由系统管理员完成,需要专门的授权页面,对UCD的要求比较高。阿里使用的是一套ACL的系统,在程序员开发了一个新页面之后,需要到ACL系统创建一个页面资源(要求准确填上URL),再创建一个权限匹配这个资源,最后把权限赋予允许访问的用户或者角色。然后此用户就可以在生产环境访问此新页面了

分域设计

上述基于RBAC的方案,解决了分权的问题,那么为什么还需要分域?

考虑以下场景,用户A和B分别是2个部门的主管,显然他们都有权限给下属员工打绩效。所以无论菜单、页面、API、员工表,A和B的权限应该是一致的,但是他们应该只能给自己部门的员工打绩效。这个场景光靠权限无法满足,所以需要引入分域的概念

如果用分权的思路,能不能满足这个场景呢?似乎也是可以的,如果把权限控制的粒度做到数据行级,好像也是个办法,但是这样实现比较困难。

总而言之,在我的理解里,在分权的基础上,分域是为了解决“同等权限下,访问不同域的数据”的问题

基本的思路,是在业务模型上增加域ID,同时用户也有自己的域ID。然后在访问数据的控制点上,除了要检查是否有权限,还要增加检查域的逻辑,即用户的域ID,与业务模型的域ID是否匹配

E-R图

前面分权的E-R图,在增加分域能力后,应该扩展成下图

ER

域分配

同理,域也需要分配。不过比起分配权限,分配域的操作要容易一些。主要是在新增用户的时候,填写域字段,比如部门、单位等

多租

最后澄清“分域”和“多租”的概念,有时会有些混淆。

从实现效果来看,两者确实有类似之处。一个域的用户,无法访问其他域的数据。类似的,隶属于一个租户的用户,也无法访问另一个租户空间下的数据。从这个角度看,确实有点像。

但是实际上,多租强调的并不是“数据可见性”,而是“隔离”。租户之间数据不可见,只是隔离的其中一个方面,或者说是隔离的副产品。

多租要达到的目标,是租户间的资源隔离,使得每个租户都以为系统是专门为自己服务的。更多的是稳定性、商业模式上的考虑。

分域要达到的目标,是业务数据展示给不同用户,是特性的考虑。

支持多租的系统一定有分域的特性

支持分域的系统一定支持多租户

以上两条命题均为假。