senline

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

说明:

这是10多年前(2011年前后)实现的基于资源的属性的权限控制实现。今天看到一篇文章(企业管理系统前后端分离架构设计 系列一 权限模型篇 - 若邪 - 博客园 (cnblogs.com)里提到里几种权限模型,比如acl,rbac,最吸引我的是作者提到了ABAC(Attribute-Based Access Control)(基于属性的权限控制),ABAC这个名词是我第一次听说,但使我想起了10年前实现的一个方案,和这个比较类似,又从故纸堆里翻出来,放在这里。文章成文于约2011年前后,是我离开项目后,交接时写的一篇原理性的文档,所以文中有些内容比较具体,也欠高度,比如文中的持久层,是说的系统中实现的一种类似于hibernate的数据持久化框架,也就是 dao层。这个方案的基本原理就是,使用资源(权限控制对象,比如合同,订单,入库单)的属性(甚至属性的属性,比如合同类型、合同供应商、合同的供应商的所属地区,也即合同.供应商.地区)来控制对资源的操作(增删改查,操作也是可定义的,比如可以增加打印操作)

---------------------------- 

 

1.    原理与概念

1.1.     与持久层的集成

数据权限与持久层集成。

(1)        在持久层查询的时候,会调用数据权限模块,形成Join 或者IN 的SQL语句,与持久层的查询SQL拼成带权限控制的SQL语句。

(2)        持久层修改数据的时候(比如插入Insert,删除delete,修改Update,查询View),会调用数据权限模块,判断当前用户是否具有该实体的某种权限

1.2.     几个概念

(1)        控制的资源(Resource)

是指权限控制的对象,要控制对谁的操作权限。比如资产,部门等等。

(2)        数据权限控制的维度

维度的概念

某个实体的数据权限,可以通过它的某些列来控制(现在只支持实体类的列)。比如通过资产类别和(或者)成本中心来控制对资产主数据的操作权限,具体讲,就是,某个用户可以修改某个或某几个成本中心的资产,可以修改某个或某几个类别的资产。我们称资产类别和成本中心是控制的维度。

可以同时通过多个维度控制某个实体的操作权限。

维度之间的关系

多个维度之间可以是And的关系,或者Or的关系。比如,通过资产类别和成本中心控制对资产的修改权限。在and的关系时,只有根据资产类别和成本中心判断,都有对资产的某个修改权限时,才可以对资产进行修改。Or的关系时,只要根据资产类别或者成本中心判断对资产具有修改的权限,则对资产具有修改权限。 

1.3.     数据权限与功能结合

以前的数据权限只能针对实体来定义,一旦定义了对某个数据的权限,则在所有功能中都有效,这在某些场合下是不合适的。

新的版本实现了功能与数据权限的结合,也就是说,可以定义在某个功能下对资产数据可以修改,再另外的功能下,不可以对资产数据进行修改。 

2.    实现

2.1.     要控制哪些实体的权限

并不是所有的实体的权限都需要控制。需要控制哪些实体的权限,在表access_ctrl_resx中定义。该表除了定义了要控制哪些数据权限之外,还定义了用于控制实体权限的实体,比如,资产管理类别。通常并不需要控制资产管理类别的操作权限,但是可以通过资产管理类别来控制资产的修改权限。

<缺少对通过简单编码类实现的实体的定义的说明,有识之士可以补充预制语句的预制方式>

2.2.     实体之间的关系

实体之间的关系,用来定义某个实体可以用什么实体来控制数据权限。比如资产与资产类别有关系,则可以通过资产类别来控制资产的修改权限。

实体关系定义在access_ctrl_resx_relation表中。一般实体之间的关系不用特别定义,因为实体结构表(entity_map_info)中已经定义了实体间的关系。只有与通过简单编码类实现的实体的关系需要特别定义,因为不同的实体,是用的相同的类(simpleNumber)来实现的,如果不特别定义,系统没法区分。

<缺少对通过简单编码类实现的实体的定义的说明,有识之士可以补充预制语句的预制方式>

参见预置语句和视图 v_access_ctrl_resx 和 v_access_ctrl_resx_relation。

2.3.     界面

 

 

 

  

2.4.     权限控制定义数据存放表

(1)access_ctrl_matrix 存放用户对某个实体+功能的权限控制定义数据表头。

  

(3)    access_ctrl_matrix_item存放权限定义的行项目,可以是多维的,通过resource_control_by来区分维度

   

2.5.      关于功能号

前面说过,数据权限可以定义到功能。那么客户端如何将当前打开的功能号传递到服务端的权限控制程序呢。

(1)客户端

在打开一个功能或者切换功能窗口时,使用 形如System.Runtime.Remoting.Messaging.CallContext.SetData("function", “0101”)

的代码在客户端传递当前所在的功能号。在向服务端请求数据时(sendInfo方法),使用System.Runtime.Remoting.Messaging.CallContext.GetData("function")取得功能号,附加到请求数据中。

窗口必须从FormBase继承,程序从FormBase.FuncNo取功能号,否则传过去的功能号为null。

(2)服务端

解析客户端的数据,取出功能号,放到Session中。服务端通过Session传递功能号。 

2.6. 如何与持久层结合

分两种情况:数据查询和对某个实体进行增删改查等操作。

(1)    查询

比如持久层的Query。这种情况,权限程序通过形成可以与查询sql组织在一起的In语法或者Join语法的SQL语句,来实现对数据权限的控制。

形如:

select a.anln1, a.txt50

  from amsap_anla a

  join access_ctrl_idset0 c on a.gdlgrp_id = c.id

或者

select a.anln1, a.txt50

  from amsap_anla a

  where a.asset_id in (select  from oid form access_ctrl_idset0 where …)


其中下划线部分是权限程序形成的sql语句。

(2)        对某个实体进行增删改查等操作

举例来讲,是判断对内码为12333的资产是否有修改的权限。特定操作包括查看,修改,删除,新增。 

2.7.      权限控制语句的形成

(1)Join语句

如果是通过一维控制

比如资产通过 “所属成本中心.利润中心”来控制,首先权限程序先形成权限定义的所有利润中心的内码,存放在access_ctrl_idsetX表中,并形成类似下面的划线部分的sql语句。最终形成的join语句类似:

Select … from 资产表

Join 成本中心表on 资产表.成本中心 = 成本中心表.内码

Join access_ctrl_idset0 on 成本中心表.所属利润中心 = access_ctrl_idset0.内码

and access_ctrl_idset0.xxx=xxx and …

其中下划线部分是权限程序形成的语句。access_ctrl_idset0中存放了定义的利润中心的内码。 

如果是通过多维控制,又分两种情况。

A.   多维之间是and 的关系

假设分别通过 成本中心和资产类别控制资产的权限。

形成的join语句类似:

 Select … from 资产表

  Join access_ctrl_idset0 on 资产表.成本中心= access_ctrl_idset0.内码

and access_ctrl_idset0.entity_name = ‘成本中心

  Join access_ctrl_idset1 on 资产表.资产类别= access_ctrl_idset1.内码

and access_ctrl_idset1.entity_name = ‘资产类别

access_ctrl_idset0 和 access_ctrl_idset1分别存放数据权限表中定义的资产类别和成本中心的内码,这两个表中的数据由权限分析程序动态形成。

B.   多维之间是or的关系

这种关系下,权限程序要根据每个维度定义(可以查看的),形成有权察看的资产的内码清单。

 Select … from 资产表

  Join access_ctrl_idset0 on 资产表.内码= access_ctrl_idset0.内码

and access_ctrl_idset0.entity_name = ‘资产

access_ctrl_idset0中存放的实资产的内码。表中的数据由权限分析程序动态形成。

多维or的关系,权限控制会导致性能下降。因为要根据多个维度形成有权限查看的资产内码的清单,有时候这个数据量是很大的。

 (2)In 语句

权限程序要根据每个维度定义(可以查看的),形成有权察看的资产的内码清单,存放在access_ctrl_idsetX表中。

 Select … from 资产表

where 资产表.内码 in( select 内码 from access_ctrl_idset0 where entity_name = ‘资产’)

其中下划线部分是权限程序形成的语句。access_ctrl_idset0中存放的实资产的内码,表中的数据由权限分析程序动态形成。

2.8.      数据缓存

为提高效率,权限程序做了三类缓存,一是数据权限定义数据,二是已经断言的对某个实体的某种操作是否有权限,三是每个用户每个实体的的操作的权限语句(上面的下划线部分的语句)也给缓存下来了。缓存的key是 用户+功能号+操作(查询)+实体名称。

缓存失效

当通过界面修改数据权限时,会修改一个标志:权限修改时间。权限处理程序检查该状态,以便确定缓冲是否失效。失效后,清除所有缓存,以及access_ctrl_idsetX中的数据。

2.9.      源码

项目EAFBaseLayer\PanFis.Authorization

项目EAFBaseLayer\PanFis.Authorization .Defination

项目EAFBaseLayer\PanFis.Authorization .Implementation 

3.    access_ctrl_idsetx表

权限程序使用access_ctrl_idsetx表来存放权限运算时的数据。

系统初始化时生成了x个 access_ctrl_idset 表,名称分别是 access_ctrl_idset0, access_ctrl_idset1, access_ctrl_idset2,……access_ctrl_idsetx-1。

系统随机选择一个表使用,以避免“热表”出现,影响效率。 

4.    几个全局变量

有几个全局的可配置变量对数据权限起作用。

4.1.      是否控制数据权限

  

4.2.     “未定义数据权限时”的处理方式

如果没有定义某个数据实体的数据权限,系统应该如何处理。两个选择:

(1)没有任何权限

(2)拥有任何权限。

可以根据具体情况设置。见上图 的“控制模式”。

4.3.     维度之间的and/or关系

如果一个数据对象使用了多个维度控制,定义多维度之间的逻辑关系。

(1)        And的关系

只有所有维度都有某个权限是,才具有对该对象的这个操作权限。

(2)        OR的关系

只要某个维度具有某个权限,则具有对该对象的这个操作权限。

And/OR关系,在pub_config中定义,配置变量名称:

如果没有定义,默认为OR。

4.4.     是否针对右键帮助窗口控制权限

如果系统参数“右键帮助权限控制”打勾,并且针对右键帮助定义了数据权限(右键帮助窗口作为一个内部功能来看待,功能编号是“DIHW”),则在弹出右键帮助的时候,会使用针对右键帮助这个内部功能定义的数据权限,而忽略掉弹出右键帮助的功能的权限定义(因为弹出右键帮助的时候,功能号改成了右键帮助(DIHW))。  

5.    几个特殊的权限定义行

在定义权限的时候,有几种行数据:

(1)        以下列出之外的”xxx”

(2)        当前用户所属的“xxx”

(3)        具体的行。 

5.1.     以下列出之外的”XXX”

是一种“排他”性质的定义。比如,你定义了对“部门0101”和“部门0102”的资产有修改的权限,那对除了这两个部门之外的资产呢,用“以下列出之外的”来定义。

5.2.     当前用户隶属的”xxx”

只有与用户有关系的对象,才会出现这一行,比如部门,因为用户隶属于部门。 

6.    改进

6.1.     IN语法

IN语法可能会导致效率降低,可以考虑增加一种Exists类型语法。 

6.2.     当多维度之间是OR的关系时

现在权限程序形成的是控制实体的内码清单,与控制的实体进行关联,形成内码清单时,如果数据量比较大, 效率会很低。

posted on 2021-12-01 09:34  森蓝2010  阅读(690)  评论(0编辑  收藏  举报