分权分域设计
总结对分权分域的理解和方案设计
第一次实现RBAC的权限管理系统,已经是十几年前的事了。但至今,我还是无法确定“分权分域”,是一个词还是两个词,说的是一件事还是两件事。尝试google了一下,也没有找到确切的答案。本文记录一下个人的理解。
概念
我在网上看到以下说法,
分权分域,是权限管理系统所能实现的效果之一,简单来说就是两点:
分权,定制用户权限,不同的用户登录系统后的界面不同,所能进行的操作也不同。
分域,控制用户权限,防止越权访问和跨域访问。
按这种说法,“分权分域”说的就是一件事,分权是定义权限,分域是分配权限。我在网上没有找到标准的概念。
我个人的理解,是把“分权”和“分域”看作2件不同的事情。分权解决“用户能操作什么资源”的问题,分域解决“在有权限的前提下,用户能看到哪些数据”的问题。我不确定这种理解对不对,下文都以这种理解为基础。
分权设计
分权的设计,基本上参考RBAC就很完善。简而言之,大致是以下几个思路
- 每个“资源”都有ID,比如菜单项、页面、API、数据库表都是资源,跟“权限”一一对应
- 用户有N个权限,当用户请求资源时,检查用户是否有相应的权限,如果没有就拒绝请求
- 为了方便给用户授权,引入“角色”的概念,避免重复操作
E-R图
控制点
有了资源和对应的权限模型之后,需要针对不同的资源类型,在加载的入口增加权限控制的逻辑
通常来说,常见的资源类型有:
- 菜单,决定是否展示某个菜单项
- 页面,表现为URL,决定用户是否可以访问某个页面
- API,后端接口是否允许调用
- 数据库表,某张表是否可以访问。可以细化为针对CRUD设置不同的权限
以API类型的资源为例,在调用API的入口,检查用户的权限,如果没有权限则拒绝调用。其他的控制点都类似,不赘述
要点是,创建权限时,通常需要设置一个KEY_CODE,或者符合某种命名规则。因为控制点的校验代码需要有某种规则来匹配权限
如果用KEY_CODE,控制逻辑类似于:
1 | String GET_BALANCE_API = "get_balance_api";// 权限的标识 |
可以发现,这样比较麻烦,因为在每个API的入口,都需要检查KEY_CODE是否符合。如果设计一个命名规则,在创建资源和权限时,都遵循这个命名规则,那么就可以写通用的校验逻辑
权限分配
资源和权限配置完成以后,需要分配给用户。由于用户很多,批量处理会很困难,所以引入角色的模型。这也是RBAC的精髓之一
授权操作通常由系统管理员完成,需要专门的授权页面,对UCD的要求比较高。阿里使用的是一套ACL的系统,在程序员开发了一个新页面之后,需要到ACL系统创建一个页面资源(要求准确填上URL),再创建一个权限匹配这个资源,最后把权限赋予允许访问的用户或者角色。然后此用户就可以在生产环境访问此新页面了
分域设计
上述基于RBAC的方案,解决了分权的问题,那么为什么还需要分域?
考虑以下场景,用户A和B分别是2个部门的主管,显然他们都有权限给下属员工打绩效。所以无论菜单、页面、API、员工表,A和B的权限应该是一致的,但是他们应该只能给自己部门的员工打绩效。这个场景光靠权限无法满足,所以需要引入分域的概念
如果用分权的思路,能不能满足这个场景呢?似乎也是可以的,如果把权限控制的粒度做到数据行级,好像也是个办法,但是这样实现比较困难。
总而言之,在我的理解里,在分权的基础上,分域是为了解决“同等权限下,访问不同域的数据”的问题
基本的思路,是在业务模型上增加域ID,同时用户也有自己的域ID。然后在访问数据的控制点上,除了要检查是否有权限,还要增加检查域的逻辑,即用户的域ID,与业务模型的域ID是否匹配
E-R图
前面分权的E-R图,在增加分域能力后,应该扩展成下图
域分配
同理,域也需要分配。不过比起分配权限,分配域的操作要容易一些。主要是在新增用户的时候,填写域字段,比如部门、单位等
多租
最后澄清“分域”和“多租”的概念,有时会有些混淆。
从实现效果来看,两者确实有类似之处。一个域的用户,无法访问其他域的数据。类似的,隶属于一个租户的用户,也无法访问另一个租户空间下的数据。从这个角度看,确实有点像。
但是实际上,多租强调的并不是“数据可见性”,而是“隔离”。租户之间数据不可见,只是隔离的其中一个方面,或者说是隔离的副产品。
多租要达到的目标,是租户间的资源隔离,使得每个租户都以为系统是专门为自己服务的。更多的是稳定性、商业模式上的考虑。
分域要达到的目标,是业务数据展示给不同用户,是特性的考虑。
支持多租的系统一定有分域的特性
支持分域的系统一定支持多租户
以上两条命题均为假。