X0 上期回顾
上文《大型Saas系统的权限体系设计(一)》提到2B的Saas系统的多层次权限体系设计的难题,即平台、平台的客户、客户的客户,乃至客户的客户的客户如何授权,这个可以通过“权限-角色-岗位”三级结构来实现。
但这个只是功能权限,如何在数据权限上进行区分和约束呢?比较极端的做法是在岗位设置上设定数据访问权限,但这会带来一个问题,即每个岗位几乎要等同于权限,需要拆分得很细,这会给管理员带来巨大的配置工作负担。所以比较巧妙的办法是把数据权限的控制拆分成宏观和微观,并且做解耦处理。
X1 行级数据权限控制
宏观数据权限控制,也可以称作行级数据权限控制,即管控到每一条数据记录的可访问范围。这个可以通过在“角色”这个实体上进行定义即可,即包括:
- 本人
- 本人即下属
- 本部门
- 指定个人
- 指定部门
- 全部
如果是“指定个人”和“指定部门”,只要设置具体的个人集合或者部门集合,即可限制该角色可访问的数据范围。
如果是对“本人及下属”,相对麻烦点。因为个人和个人之间的汇报关系比较难设定。而大型组织中常常会存在部门负责人和部门分管领导的管理结构,特别是OA审批中,经常会出现“发起人部门领导审批”和“发起人部门分管领导审批”这类设置,比较难以在组织结构和角色上进行实现。如果直接在用户基础上设立“直属上级”,又会带来另一个不好的结果,即如果领导调离会需要修改一大批下属的“直属上级”,一旦修改不及时就可能导致审批权限的混乱。
比较好的解决办法是把上下级关系建立在部门岗位基础上,由岗位形成上下级关系,而个人可以设定多个岗位,则人与人之间的上下级关系自然而然建立,同时又避免了因为上级岗位变动带来的不必要的大面积变更。
X2 列级数据权限控制
微观数据权限控制,也可以称作列级数据权限控制,即管控到每种业务数据的字段的可访问范围。这个控制相对比较复杂,成本也比较高。
如果建立在权限基础上,会导致权限需要拆分得很细。如果建立在角色基础上,又会对角色的大颗粒度造成破坏。而且,一旦把列级数据权限和行级数据权限纠结在一起,很容易形成渔网效应,失去应有的灵活性和适应性。
所以比较好的解决办法是把列级数据权限和行级数据权限解耦,即可以对列级数据权限单独管理,有需要做列级数据权限管理的业务数据才动态添加。而且列级数据权限控制最好控制到岗位这个级别。如下图:
X3 多租户的权限区隔
再回归到最初的议题,如果对于Saas系统,存在多租户,甚至租户有客户的情况下,如何对不同类型的客户的权限进行区隔?或者是否可以进行区隔,并且部分下放权限设置的权限呢?
答案是肯定的,而且必须下放。
设想下,一个成功的Saas系统,用户少则几万,多则千万,如果这么多的用户的权限管理都归于平台管理员一身,本身就是巨大的成本。所以下放权限管理功能是毋庸置疑的。但怎么下放呢?
- 首先,权限这级应该是收归平台层管理的,角色这级部分也可以归平台层管理,主要是多数租户可以共用的角色。但租户和客户管理员,应该被授予角色创建的权限,这样才可能适应不同组织的特点设计不同的角色。
- 其次,角色应该有权属的概念,即A租户创建的角色和B租户创建的角色是不可以共用的,A租户创建的角色原则上也不适用于A租户的客户。
- 其次,对于权限应该设定适合的角色类型。这样各级管理员在创建用户角色时,将只能在限定的权限范围内去做角色的权限授权(很难想象,你客户的管理员可以在创建角色时看到你平台所有的菜单权限,OMG)。
- 最后,光有权限和角色还不够,非常有必要增加“岗位”的概念。这个岗位虽然只对应一个角色,但同时需要明确所属部门(或组织),这样角色才可能得到最大程度的复用。现实生活中,不同部门的相同职位的管理人员既有相似的工作职能,也可能有不同的工作职能,所以光通过角色去设置可能导致不必要的冲突。
只要我们把角色、岗位之类的权限设置也看成一种数据,并且纳入数据权限控制的范畴,那么多租户的权限区隔就很容易实现了。
X4 结束语
近期也看到有一个开源的授权库模型 Casbin(一个支持如ACL, RBAC, ABAC等访问模型,可用于Golang, Java, C/C++, Node.js, Javascript, PHP, Laravel, Python, .NET (C#), Delphi, Rust, Ruby, Lua (OpenResty), Dart (Flutter)和Elixir的授权库。),国外应用极广。
结合以上拙文,供遇到相同问题并且在思考解决办法的同行参考。赠人玫瑰,手有余香,欢迎不吝赐教或者技术交流。