通用权限管理设计之数据权限.docx
《通用权限管理设计之数据权限.docx》由会员分享,可在线阅读,更多相关《通用权限管理设计之数据权限.docx(10页珍藏版)》请在冰豆网上搜索。
![通用权限管理设计之数据权限.docx](https://file1.bdocx.com/fileroot1/2022-12/13/5711ce1b-00f4-465d-968d-2505b0fd1638/5711ce1b-00f4-465d-968d-2505b0fd16381.gif)
通用权限管理设计之数据权限
通用权限管理设计之数据权限
阅读目录
前言
初步分析
通用查询机制
数据权限规则
实际应用
结语
前言
前一篇文章《通用权限管理设计之数据库设计方案》介绍了【主体】-【领域】-【权限】(who、what、how问题原型)的设计思想
本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案。
权限控制可以理解,分为这几种:
【功能权限】:
能做什么的问题,如增加产品。
【数据权限】:
能看到哪些数据的问题,如查看本人的所有订单。
【字段权限】:
能看到哪些信息的问题,如供应商账户,看不到角色、部门等信息。
上面提到的那种设计就是【功能权限】,这种设计有一定的局限性,对于主体,只能明确地指定。
对于不明确的,在这里可能就没办法处理。
比如下面这几种情况:
数据仅当前部门及上级可见
数据仅当前用户(本人)可见
类似这样的就需要用到上面提的数据权限。
上一篇文章我用一个表五个字段完成了【功能权限】的设计思路
本文我将介绍如何利用一个表两个字段完成这个【数据权限】的设计思路初步分析
【数据权限】是在【功能权限】的基础上面进一步的扩展,比如可以查看订单属于【功能权限】的范围,但是可以查看哪些订单就是【数据权限】的工作了。
在设计中,我们规定好如果没有设置了数据权限规则,那么视为允许查看全部的数据。
几个概念
【资源】:
数据权限的控制对象,业务系统中的各种资源。
比如订单单据、销售单等。
属于上面提到的【领域】中的一种
【主体】:
用户、部门、角色等。
【条件规则】:
用于检索数据的条件定义
【数据规则】:
用于【数据权限】的条件规则
应用场景
1,订单,可以由本人查看
2,销售单,可以由本人或上级领导查看
3,销售单,销售人员可以查看自己的,销售经理只查看销售金额大于100,000的。
我们能想到直接的方法,在访问数据的入口加入SQLWhere条件来实现,组织sql语句:
1,whereUserID={CurrentUserID}
2,whereUserID={CurrentUserID}or{CurrentUserID}in(领导)3,whereUserID={CurrentUserID}or({CurrentUserID}in(销售经理)and销售金额>100000)
这些一个一个的"条件",本文简单理解为一个【数据规则】,通常会与原来我们前台的业务过滤条件合并再检索出数据。
这是一种最直接的实现方式,在【资源】上面加一个【数据规则】(比如上面的三点)。
这样设计就是
【资源】-【数据规则】
我又觉得不同的人应该对应不同的规则,那么也可以理解为,一个用户对应不同的角色,每一个角色有不一样的【数据规则】,那么设计就变成
【资源】-【主体】-【数据规则】
根据提供者的不同,准备不同的权限应对策略。
这里可以简单地介绍一下,这个方案至少需要2张表,一个是【资源,主体,规则关系表】、一个是【数据规则表】
关系表不能直接保存角色,因为你不确定什么时候业务需要按照【部门】或者【分公司】来定义数据规则
于是可以用Master、MasterKey类似这样的两个字段来确定一个【主体】用XML方式的话是这样配置的(放在数据库也类似):
xmlversion="1.0"encoding="utf-8"?
>
销售员={CurrentUserID}
销售金额>100000
销售金额>100000and区域={当前用户所属区域}
对于这种方式有兴趣的朋友也可以试一下,两种方式的【数据规则】是一样的,但是本文没有采用第二种设计方式,因为它多了一层处理逻辑,我以为应该设计越简单越好,就采用第一种方式:
【资源】-【数据规则】
当然,上面是用SQL的方式来确定条件规则的,我们当然不会这么做。
SQL虽然灵活,但是我们很难去维护,也不知道SQL在我们的界面UI上面如何体现。
难不成直接用一个文本框来显示。
这样对应一个开发人员来说不是问题,可是对应系统管理员,很容易出问题。
所以我们需要有另一方式来确定这一规则,并最终可以转换成我们的SQL语句。
我们的设计关键在于如何规范好这些【数据规则】,这个规则必须是对前端友好的,而且是对后台友好的,JSON显然是很好的方式。
规则说明:
1,数据权限规则总是:
属性条件允许值,
2,数据权限规则可以合并。
比如({当前用户属于销售人员}and{订单销售员等于当前用户})Or{当前用户属于销售经理}
3,最终我们会用JSON格式
在检索数据时会先判断有没有注册了某某【资源】的【条件规则】,如果有,那么加载这个【条件规则】并合并到我们前台的【搜索条件】(你的业务界面应该有一个搜索框吧)
如下图定义了客户信息的搜索框,我们搜索客户ID包括AN,我们组织成的规则将会是:
{"rules":
[{"field":
"CustomerID","op":
"like","value":
"AN","type":
"string"}],"op
":
"and"}
为了更好地理解【数据规则】,这里介绍一下【通用查询机制】
【通用查询机制】
权限控制总离不开一些条件的限制(比如查看当前部门的单据),如果没有完善的通用查询规则机制,那么在做权限条件过滤的时候你会觉得很别扭。
这里介绍一个通用查询方案,然后再介绍如何实现【数据规则】。
早些时候我写过一篇关于ligerGrid结合.net设计通用处理类的文章《jQueryligeruiligerGrid打造通用的分页排序查询表格(提供下载)》。
里面提到的过滤信息是直接的SQL语句。
这是不可靠,而且不安全的。
在前端传输给后台的过滤信息不应该是直接的SQL,而应该是一组过滤规则。
在ligeruiV1.1.8已经加入了一个条件过滤器插件,这个插件组成的规则数据才是我受推荐的:
比如如下
{"rules":
[
{"field":
"OrderDate","op":
"less","value":
"2012-01-01"},{"field":
"CustomerID","op":
"equal","value":
"VINET"}]
"op":
"and"}
规则描述:
查找顾客VINET所有订单时间小于2011-01-01的单据
这样的数据是安全的,而且是通用的(你甚至可以再加一个OR子查询)。
无论是在前端还是后台,无论你使用什么样的组件,都可以很好地利用。
通用后台的翻译,就可以生成这样SQL的参数:
Text:
([OrderDate]<@p1and[CustomerID]=@p2)
Parameters:
p1:
2012-01-01
p2:
VINET
下面来点复杂的:
查找顾客VINET或者TOMSP,所有订单时间小于2011-01-01的单据
{
"rules":
[{"field":
"OrderDate","op":
"less","value":
"2012-01-01"}],
"groups":
[
{"rules":
[{"field":
"CustomerID","op":
"equal","value":
"VINET"},
{"field":
"CustomerID","op":
"equal","value":
"TOMSP"}],"op":
"or"}
],
"op":
"and"
}
翻译结果:
Text:
([OrderDate]<@p1and([CustomerID]=@p2or[CustomerID]=@p3))Parameters:
p1:
2012-01-01
p2:
VINET
p3:
TOMSP
这个过滤规则分为三个部分:
【分组】、【规则】(字段、值、操作符)、【操作符】(andor),而自身就是一个分组。
这种简单的结构就可以满足全部的情况。
当然,上面提到的这些条件都是在前台定义(可能是用户在搜索框自己输入的)的,而在后台,我们可能会定义一下【隐藏条件】,比如说【员工只能查看自己的】,要怎么做呢,其实很简单,只需要在后台接收到这个过滤条件(前台toJSON,后台解析JSON)以后,再加上一个过滤规则(隐藏条件):
{field:
'EmployeeID',op:
'equal',value:
5}
可以将原来的过滤规则当做一个分组加入进行:
{op:
'and',groups:
[
{"rules":
[{"field":
"OrderDate","op":
"less","value":
"2012-01-01"}],
"groups":
[
{"rules":
[{"field":
"CustomerID","op":
"equal","value":
"VINET"},{"field":
"Custo
merID","op":
"equal","value":
"TOMSP"}],"op":
"or"}],"op":
"and"}
],rules:
[{field:
'EmployeeID',op:
'equal',value:
5}]}
翻译如下:
Text:
([EmployeeID]=@p1and([OrderDate]<@p2and([CustomerID]=@p3or[CustomerID]=@p4)))
Parameters:
p1:
5
p2:
2012-01-01
p3:
VINET
p4:
TOMSP
这样的【条件规则】才是我们想要的,不仅在前端可以很好地解析,也可以在后台进行处理。
在后台我们会定义跟这种数据结构对应的类,那么再定义一个翻译成SQL的类:
数据权限规则
说了这些,可以开始介绍如何实现【数据规则】了:
上面提到的【隐藏条件】,就是我介绍的【数据规则】
试想一些,这样前台的过滤规则,再加上我们之间定义好的【数据权限】控制过滤条件。
不就达到目的了吗。
先看看我们在数据库里保存的这些【数据规则】:
看不明白,那来个清楚一点的:
规则描述
订单:
【订单管理员和演示角色可以查看所有的】,【订单查看员】只能查看自己的
产品:
【基础信息录入员和演示角色可以查看所有的】,【供应商】只能查看自己的{CurrentEmployeeID}表示当前的员工。
实质上,我们还可以根据当前用户信息定义需要的参数,比如:
{CurrentUserID}当前用户Id,对应表【CF_User】
{CurrentRoleID}当前角色Id,对应表【CF_Role】
{CurrentDeptID}当前用户部门Id,对应表【CF_Department】
{CurrentEmployeeID}当前用户员工Id,对应表【Employees】(CF_User.EmployeeID){CurrentSupplierID}当前用户供应商Id,对应表【Suppliers】(CF_User.SupplierID)
在数据库中我们直接保存这些用户参数,在“翻译”规则成为SQL时,会替换掉:
比如查看订单,我们得到的SQL,可能是这样的:
Text:
SELECT*FROM(SELECTTOP20*FROM(SELECTTOP40*FROM[Orders]WHERE(1=1and((@p1in(@p2,@p3))or(@p4=@p5and[EmployeeID]=@p6)))ORDERBYOrderIDASC)AStmptableinnerORDERBYOrderIDDESC)AStmptableouterORDERBYOrderIDASCParameters:
@p1[Int32]=7
@p2[Int32]=2
@p3[Int32]=6
@p4[Int32]=7
@p5[Int32]=7
@p6[Int32]=1
{CurrentRuleID}替换为7
{CurrentEmployeeID}替换为1
下图是我们设计【数据权限】的界面,可以选择所有的字段,包括几个用户信息:
这些字段不仅仅只是在文本框中输入值,那么可以自定义数据来源:
varfieldEditors={};
fieldEditors['Orders']={
'ShipCity':
{type:
'combobox',
options:
{
width:
200,
url:
"../handler/select.ashx?
view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=
true"
}
}
};
效果界面:
实际应用
既然是数据权限控制,如果有一个统一的数据接收入口,我们倒是可以利用这个入口做一些工作。
比如【ligerRM权限管理系统】统一使用grid.ashx这个数据处理程序作为列表数据的接收入口。
有了统一的接口,方便做权限的控制,使用过ligerGridJavascript表格,或者类似插件的朋友,应该比较清楚服务器的交互原理。
在grid.ashx中,我们会通过
【视图/表名】、【排序信息】、【分页信息】、【过滤信息】
这几个指标来获取指定的数据。
而在实际的业务中,可能会引入权限的控制。
比如某某【资源】,只能由当前用户自身才能查看,或者只能由当前用户部门及上级部门才能查看。
对于这些控制,我们采用对这些可能做权限控制的【资源】注册一组【条件规则】的方式来进行。
我们将找到view定义好的【数据权限规则】,然后和用户在前台搜索框输入的【搜索规则】
合并:
上面的代码就是数据条件合并的例子,这样便得到了我们最终需要的过滤规则。