精华内容
下载资源
问答
  • 众所周知 数据后台是较为复杂的系统,本后台axure原型包含了“订权限分配”、“数据客户死后”、“门户统计”、“用户分析” 可以帮助想要入门数据产品经理的同学,对后台系统有一个直观、便捷的了解!
  • 目录1....在本篇文章,我会以ERP系统最成熟的后台管理系统来举例子,从顶层业务开始分析、再到底层数据关系,最后通过原型说明。 1.业务流程 ERP系统,Enterprise Resource Planning,企业资源计...


    B端产品做了这么久,最大的感触就是B端产品有着复杂的业务关系。凡事预则立,那么在规划一个模块的功能之前,我们需要先对这个模块内部的业务关系进行梳理。在本篇文章,我会以ERP系统最成熟的后台管理系统来举例子,从顶层业务开始分析、再到底层数据关系,最后通过原型说明。

    1.业务流程

    ERP系统,Enterprise Resource Planning,企业资源计划。顾名思义,首先企业资源有哪些?我们看到的金蝶、用友、SAP等ERP系统,在系统部署时,实施顾问总会先提到一个词:后台管理系统。后台管理系统也是给用户用的,提到后台管理系统肯定离不开一个词叫权限。权限管理主要是避免因权限控制缺失而引起的数据泄露的问题。所以,我们需要解决的问题是:

    哪些部门的哪个用户具有哪些权限?

    要解决这个问题,我们不得不提到一个模型:RBAC(基于角色的访问控制)权限控制模型
    因此,我们需要聚焦三个关键词:用户、角色、权限。

    在这里插入图片描述
    一个后台管理系统,关于用户、角色、权限基本上可以抽象出六张表:

    1. 部门表;一个公司可以有多个部门;
    2. 用户表;一个用户可从属于多个部门;
    3. 角色表;一个系统有多个角色,一般简单分为系统管理员administrator和普通用户user;
    4. 用户-角色表;用户角色表,即一个用户可有多个角色,存储用户和角色之间的映射关系;
    5. 权限表;权限分为页面权限、数据权限、操作权限;
    6. 角色-权限表;每个角色可以拥有哪些页面权限、数据权限以及操作权限。

    涉及到部门其实还会有一个叫用户组的概念,当用户很多时,我们给每个用户单独去赋予角色,会很麻烦。可以将一个部门下的所有用户授予一个角色。
    在这里插入图片描述

    2.数据流程

    前面一部分,分析了每个步骤的业务以及主要的作用,我们这一步主要是分析底层数据的流向。为了更加清晰,这一部分直接用Navicat进行E-R建模。

    建议每个B端产品经理都学习一下UML建模工具,对工作中的业务分析有很大的帮助。

    在这里插入图片描述

    每个表都很类似,主要是id和name。特殊说明一下,sys_role_user表,uid和rid分别通过建立外键,关联sys_user表和sys_role表。同样,sys_role_permission角色权限表,也是通过外键建立联系。

    PS:作为产品经理,只需要了解到权限是通过底层六张表来实现,具体数据库操作可以不关注。但作为开发人员,必须了解每张表如何建以及从产品业务抽象出数据库模型。

    3.功能原型

    根据前面的分析,我们先整理出整个后台权限管理系统的思维导图:
    在这里插入图片描述

    1. 组织管理
      组织管理,主要是构建公司的组织架构,B端产品尤其是大的ERP系统等,第一件事就是要解决公司的组织架构问题。涉及到底层,也就是我们前面提到的部门表。(sys_dept)
    2. 人员管理
      组织管理建立好部门的层级关系,就要引入员工信息了。涉及到底层,也就是我们前面提到的人员表。(sys_user)
    3. 权限管理
      权限管理,主要分为三类:组织管理员授权,角色授权,用户直接授权。
      (1)对于大的公司,组织管理员授权,即部门领导授权;
      (2)角色授权,即用户关联角色,给某一角色统一授权;(sys_role_user);
      (3)用户直接授权,对于公司规模较小,可对用户直接进行授权。

    权限主要分为:
    功能权限、字段权限、数据规则。也就是我们前面提到的页面权限、数据权限、操作权限。

    1. 许可管理
      B端系统,使用是有限制的。一般公司会卖license。通俗一些说,有多少个可以登录系统的许可。
      权限分配和许可分配缺一不可。
      许可分配:用户凭账号密码可以登录系统;
      权限分配:登陆之后,能使用什么功能,取决于权限管理给该用户分配了什么权限。

    登录页
    在这里插入图片描述
    首页
    在这里插入图片描述

    此处原型只展示一个导航,具体原型内容就不一一展示了。

    本篇博文简单分析了一下RBAC权限管理模型在实际业务中如何落地,有想法欢迎讨论。

    展开全文
  • 通用权限管理设计 之 数据权限

    万次阅读 2018-01-04 10:09:40
    本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案。 权限控制可以理解,分为这几种 : 【功能权限】:能做什么的问题,如增加产品。 【数据权限】:能看到哪些数据的问题,如查看本人的所有订单。 ...

    前言

     

    前一篇文章《通用权限管理设计 之 数据库设计方案》介绍了【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的设计思想

     

    本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案。

    权限控制可以理解,分为这几种 :

    【功能权限】:能做什么的问题,如增加产品。
    【数据权限】:能看到哪些数据的问题,如查看本人的所有订单。
    【字段权限】:能看到哪些信息的问题,如供应商账户,看不到角色、 部门等信息。

    上面提到的那种设计就是【功能权限】,这种设计有一定的局限性,对于主体,只能明确地指定。对于不明确的,在这里可能就没办法处理。比如下面这几种情况:

    数据仅当前部门及上级可见
    数据仅当前用户(本人)可见

    类似这样的就需要用到上面提的数据权限。

    上一篇文章我用一个表五个字段完成了【功能权限】的设计思路
    本文我将介绍如何利用一个表两个字段完成这个【数据权限】的设计思路

    初步分析

    【数据权限】是在【功能权限】的基础上面进一步的扩展,比如可以查看订单属于【功能权限】的范围,但是可以查看哪些订单就是【数据权限】的工作了。

    在设计中,我们规定好如果没有设置了数据权限规则,那么视为允许查看全部的数据。

    几个概念
    【资源】:数据权限的控制对象,业务系统中的各种资源。比如订单单据、销售单等。属于上面提到的【领域】中的一种
    【主体】:用户、部门、角色等。
    【条件规则】:用于检索数据的条件定义
    【数据规则】:用于【数据权限】的条件规则 

     
    应用场景
    1,订单,可以由本人查看 
    2,销售单,可以由本人或上级领导查看 
    3,销售单,销售人员可以查看自己的,销售经理只查看 销售金额大于100,000的。

    我们能想到直接的方法,在访问数据的入口加入SQL Where条件来实现,组织sql语句:

    1where UserID = {CurrentUserID}
    2where UserID = {CurrentUserID}  or {CurrentUserID} in (领导)
    3where UserID = {CurrentUserID}  or ({CurrentUserID} in (销售经理)  and 销售金额 > 100000)

    这些一个一个的"条件",本文简单理解为一个【数据规则】,通常会与原来我们前台的业务过滤条件合并再检索出数据。

    这是一种最直接的实现方式,在【资源】上面加一个【数据规则】(比如上面的三点)。这样设计就是

      【资源】 - 【数据规则】

    我又觉得不同的人应该对应不同的规则,那么也可以理解为,一个用户对应不同的角色,每一个角色有不一样的【数据规则】,那么设计就变成

      【资源】 - 【主体】 - 【数据规则】

    根据提供者的不同,准备不同的权限应对策略。

    这里可以简单地介绍一下,这个方案至少需要2张表,一个是  【资源,主体,规则关系表】、一个是【数据规则表】

    关系表不能直接保存角色,因为你不确定什么时候业务需要按照【部门】或者【分公司】来定义数据规则

    于是可以用  Master、MasterKey  类似这样的两个字段来确定一个【主体】

    用XML方式的话是这样配置的(放在数据库也类似):

    <?xml version="1.0" encoding="utf-8"?>
    <settings>
      <rule view="订单" role="销售人员">
          销售员 = {CurrentUserID}
      </rule>
      <rule view="订单" role="总销售经理">
         销售金额 > 100000
      </rule>
      <rule view="订单" role="区域销售经理">
        销售金额 > 100000  and 区域 = {当前用户所属区域}
      </rule>
    </settings>

    对于这种方式有兴趣的朋友也可以试一下,两种方式的【数据规则】是一样的,但是本文没有采用第二种设计方式,因为它多了一层处理逻辑,我以为应该设计越简单越好,就采用第一种方式:

      【资源】 - 【数据规则】

    当然,上面是用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设计通用处理类的文章《 jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载) 》。里面提到的过滤信息是直接的SQL语句。这是不可靠,而且不安全的。
    在前端传输给后台的过滤信息不应该是直接的SQL,而应该是一组过滤规则。在ligerui V1.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] < @p1 and [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] < @p1 and ([CustomerID] = @p2 or [CustomerID] = @p3))
    Parameters:
    p1:2012-01-01
    p2:VINET
    p3:TOMSP

     

    这个过滤规则分为三个部分:【分组】、【规则】(字段、值、操作符)、【操作符】(and or),而自身就是一个分组。
    这种简单的结构就可以满足全部的情况。

    当然,上面提到的这些条件都是在前台定义(可能是用户在搜索框自己输入的)的,而在后台,我们可能会定义一下【隐藏条件】,比如说 【员工只能查看自己的】,要怎么做呢,其实很简单,只需要在后台接收到这个过滤条件(前台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":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
    ],"op":"and"}

     

    ],rules:[{field:'EmployeeID',op:'equal',value:5}]
    }


     

    翻译如下:

     

    Text:
    ([EmployeeID] = @p1 and ([OrderDate] < @p2 and ([CustomerID] = @p3 or [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 (SELECT TOP 20 * FROM (SELECT TOP 40 * FROM [Orders] WHERE ( 1=1  and ((@p1 in (@p2,@p3)) or (@p4 = @p5 and [EmployeeID] = @p6))) ORDER BY OrderID ASC) AS tmptableinner ORDER BY OrderID DESC) AS tmptableouter ORDER BY OrderID ASC     
    Parameters:
    @p1[Int32] = 7
    @p2[Int32] = 2
    @p3[Int32] = 6
    @p4[Int32] = 7
    @p5[Int32] = 7
    @p6[Int32] = 1

    {CurrentRuleID} 替换为 7

    {CurrentEmployeeID} 替换为1

     下图是我们设计【数据权限】的界面,可以选择所有的字段,包括几个用户信息:

    这些字段不仅仅只是在文本框中输入值,那么可以自定义数据来源:

     

    var fieldEditors = {};
    fieldEditors['Orders'] = {
        'ShipCity': { type: 'combobox', 
            options: {
                width: 200,
                url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"
            }
        }
    };

    效果界面:

     


    实际应用

    既然是数据权限控制,如果有一个统一的数据接收入口,我们倒是可以利用这个入口做一些工作。

    比如【ligerRM权限管理系统】统一使用 grid.ashx 这个数据处理程序作为列表数据的接收入口。

    有了统一的接口,方便做权限的控制,使用过 ligerGrid Javascript表格,或者类似插件的朋友,应该比较清楚服务器的交互原理。 
    在grid.ashx中,我们会通过 
    【视图/表名 】、 【排序信息】、【分页信息】、【过滤信息】
    这几个指标来获取指定的数据。


    而在实际的业务中,可能会引入权限的控制。比如某某【资源】,只能由当前用户自身才能查看,或者只能由当前用户部门及上级部门才能查看。对于这些控制,我们采用对这些可能做权限控制的【资源】注册一组【条件规则】的方式来进行。

     我们将找到view定义好的【数据权限规则】,然后和用户在前台搜索框输入的【搜索规则】合并:

    上面的代码就是数据条件合并的例子,这样便得到了我们最终需要的 过滤规则。

    结语

    本文提出了数据权限的一种实现思路,只是本人在做一个web应用时构思的方案,谈不上规范,欢迎提出你的建议意见。

    可以在http://case.ligerui.com体验实际的应用效果。

    展开全文
  • 数据权限规则 实际应用 结语 前言 前一篇文章《通用权限管理设计 之 数据库设计方案》介绍了【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的设计思想 本文将对这种设计思想作进一步的...

    前言

     

    前一篇文章《通用权限管理设计 之 数据库设计方案》介绍了【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的设计思想

     

    本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案。

    权限控制可以理解,分为这几种 :

    【功能权限】:能做什么的问题,如增加产品。
    【数据权限】:能看到哪些数据的问题,如查看本人的所有订单。
    【字段权限】:能看到哪些信息的问题,如供应商账户,看不到角色、 部门等信息。

    上面提到的那种设计就是【功能权限】,这种设计有一定的局限性,对于主体,只能明确地指定。对于不明确的,在这里可能就没办法处理。比如下面这几种情况:

    数据仅当前部门及上级可见
    数据仅当前用户(本人)可见

    类似这样的就需要用到上面提的数据权限。

    上一篇文章我用一个表五个字段完成了【功能权限】的设计思路
    本文我将介绍如何利用一个表两个字段完成这个【数据权限】的设计思路

    初步分析

    【数据权限】是在【功能权限】的基础上面进一步的扩展,比如可以查看订单属于【功能权限】的范围,但是可以查看哪些订单就是【数据权限】的工作了。

    在设计中,我们规定好如果没有设置了数据权限规则,那么视为允许查看全部的数据。

    几个概念
    【资源】:数据权限的控制对象,业务系统中的各种资源。比如订单单据、销售单等。属于上面提到的【领域】中的一种
    【主体】:用户、部门、角色等。
    【条件规则】:用于检索数据的条件定义
    【数据规则】:用于【数据权限】的条件规则 

     
    应用场景
    1,订单,可以由本人查看 
    2,销售单,可以由本人或上级领导查看 
    3,销售单,销售人员可以查看自己的,销售经理只查看 销售金额大于100,000的。

    我们能想到直接的方法,在访问数据的入口加入SQL Where条件来实现,组织sql语句:

    1,where UserID = {CurrentUserID}
    2,where UserID = {CurrentUserID} or {CurrentUserID} in (领导)
    3,where UserID = {CurrentUserID} or ({CurrentUserID} in (销售经理) and 销售金额 > 100000)

    这些一个一个的"条件",本文简单理解为一个【数据规则】,通常会与原来我们前台的业务过滤条件合并再检索出数据。

    这是一种最直接的实现方式,在【资源】上面加一个【数据规则】(比如上面的三点)。这样设计就是

      【资源】 - 【数据规则】

    我又觉得不同的人应该对应不同的规则,那么也可以理解为,一个用户对应不同的角色,每一个角色有不一样的【数据规则】,那么设计就变成

      【资源】 - 【主体】 - 【数据规则】

    根据提供者的不同,准备不同的权限应对策略。

    这里可以简单地介绍一下,这个方案至少需要2张表,一个是  【资源,主体,规则关系表】、一个是【数据规则表】

    关系表不能直接保存角色,因为你不确定什么时候业务需要按照【部门】或者【分公司】来定义数据规则

    于是可以用  Master、MasterKey  类似这样的两个字段来确定一个【主体】

    用XML方式的话是这样配置的(放在数据库也类似):

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <settings>
    <rule view="订单" role="销售人员">
    销售员 = {CurrentUserID}
    </rule>
    <rule view="订单" role="总销售经理">
    销售金额 > 100000
    </rule>
    <rule view="订单" role="区域销售经理">
    销售金额 > 100000 and 区域 = {当前用户所属区域}
    </rule>
    </settings>
    复制代码

    对于这种方式有兴趣的朋友也可以试一下,两种方式的【数据规则】是一样的,但是本文没有采用第二种设计方式,因为它多了一层处理逻辑,我以为应该设计越简单越好,就采用第一种方式:

      【资源】 - 【数据规则】

    当然,上面是用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设计通用处理类的文章《 jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载) 》。里面提到的过滤信息是直接的SQL语句。这是不可靠,而且不安全的。
    在前端传输给后台的过滤信息不应该是直接的SQL,而应该是一组过滤规则。在ligerui V1.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] < @p1 and [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] < @p1 and ([CustomerID] = @p2 or [CustomerID] = @p3))
    Parameters:
    p1:2012-01-01
    p2:VINET
    p3:TOMSP
    复制代码

     

    这个过滤规则分为三个部分:【分组】、【规则】(字段、值、操作符)、【操作符】(and or),而自身就是一个分组。
    这种简单的结构就可以满足全部的情况。

    当然,上面提到的这些条件都是在前台定义(可能是用户在搜索框自己输入的)的,而在后台,我们可能会定义一下【隐藏条件】,比如说 【员工只能查看自己的】,要怎么做呢,其实很简单,只需要在后台接收到这个过滤条件(前台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":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
    ],"op":"and"}

     

    ],rules:[{field:'EmployeeID',op:'equal',value:5}]
    }

     

     

    翻译如下:

     

    复制代码
    Text:
    ([EmployeeID] = @p1 and ([OrderDate] < @p2 and ([CustomerID] = @p3 or [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 (SELECT TOP 20 * FROM (SELECT TOP 40 * FROM [Orders] WHERE ( 1=1  and ((@p1 in (@p2,@p3)) or (@p4 = @p5 and [EmployeeID] = @p6))) ORDER BY OrderID ASC) AS tmptableinner ORDER BY OrderID DESC) AS tmptableouter ORDER BY OrderID ASC     
    Parameters:
    @p1[Int32] = 7
    @p2[Int32] = 2
    @p3[Int32] = 6
    @p4[Int32] = 7
    @p5[Int32] = 7
    @p6[Int32] = 1
    复制代码

    {CurrentRuleID} 替换为 7

    {CurrentEmployeeID} 替换为1

     下图是我们设计【数据权限】的界面,可以选择所有的字段,包括几个用户信息:

    这些字段不仅仅只是在文本框中输入值,那么可以自定义数据来源:

     

    复制代码
    var fieldEditors = {};
    fieldEditors['Orders'] = {
    'ShipCity': { type: 'combobox',
    options: {
    width: 200,
    url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"
    }
    }
    };
    复制代码

    效果界面:

     

     

    实际应用

    既然是数据权限控制,如果有一个统一的数据接收入口,我们倒是可以利用这个入口做一些工作。

    比如【ligerRM权限管理系统】统一使用 grid.ashx 这个数据处理程序作为列表数据的接收入口。

    有了统一的接口,方便做权限的控制,使用过 ligerGrid Javascript表格,或者类似插件的朋友,应该比较清楚服务器的交互原理。 
    在grid.ashx中,我们会通过 
    【视图/表名 】、 【排序信息】、【分页信息】、【过滤信息】
    这几个指标来获取指定的数据。


    而在实际的业务中,可能会引入权限的控制。比如某某【资源】,只能由当前用户自身才能查看,或者只能由当前用户部门及上级部门才能查看。对于这些控制,我们采用对这些可能做权限控制的【资源】注册一组【条件规则】的方式来进行。

     我们将找到view定义好的【数据权限规则】,然后和用户在前台搜索框输入的【搜索规则】合并:

    上面的代码就是数据条件合并的例子,这样便得到了我们最终需要的 过滤规则。

    结语

    本文提出了数据权限的一种实现思路,只是本人在做一个web应用时构思的方案,谈不上规范,欢迎提出你的建议意见。

    可以在http://case.ligerui.com体验实际的应用效果。

    转载于:https://www.cnblogs.com/roam/p/7443762.html

    展开全文
  • 阅读目录 前言 初步分析 ...数据权限规则 实际应用 结语 前言 前一篇文章《通用权限管理设计 之 数据库设计方案》介绍了【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的...

    前言

     

    前一篇文章《通用权限管理设计 之 数据库设计方案》介绍了【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的设计思想

     

    本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案。

    权限控制可以理解,分为这几种 :

    【功能权限】:能做什么的问题,如增加产品。
    【数据权限】:能看到哪些数据的问题,如查看本人的所有订单。
    【字段权限】:能看到哪些信息的问题,如供应商账户,看不到角色、 部门等信息。

    上面提到的那种设计就是【功能权限】,这种设计有一定的局限性,对于主体,只能明确地指定。对于不明确的,在这里可能就没办法处理。比如下面这几种情况:

    数据仅当前部门及上级可见
    数据仅当前用户(本人)可见

    类似这样的就需要用到上面提的数据权限。

    上一篇文章我用一个表五个字段完成了【功能权限】的设计思路
    本文我将介绍如何利用一个表两个字段完成这个【数据权限】的设计思路

    初步分析

    【数据权限】是在【功能权限】的基础上面进一步的扩展,比如可以查看订单属于【功能权限】的范围,但是可以查看哪些订单就是【数据权限】的工作了。

    在设计中,我们规定好如果没有设置了数据权限规则,那么视为允许查看全部的数据。

    几个概念
    【资源】:数据权限的控制对象,业务系统中的各种资源。比如订单单据、销售单等。属于上面提到的【领域】中的一种
    【主体】:用户、部门、角色等。
    【条件规则】:用于检索数据的条件定义
    【数据规则】:用于【数据权限】的条件规则 

     
    应用场景
    1,订单,可以由本人查看 
    2,销售单,可以由本人或上级领导查看 
    3,销售单,销售人员可以查看自己的,销售经理只查看 销售金额大于100,000的。

    我们能想到直接的方法,在访问数据的入口加入SQL Where条件来实现,组织sql语句:

    1where UserID = {CurrentUserID}
    2where UserID = {CurrentUserID} or {CurrentUserID} in (领导)
    3where UserID = {CurrentUserID} or ({CurrentUserID} in (销售经理) and 销售金额 > 100000)

    这些一个一个的"条件",本文简单理解为一个【数据规则】,通常会与原来我们前台的业务过滤条件合并再检索出数据。

    这是一种最直接的实现方式,在【资源】上面加一个【数据规则】(比如上面的三点)。这样设计就是

      【资源】 - 【数据规则】

    我又觉得不同的人应该对应不同的规则,那么也可以理解为,一个用户对应不同的角色,每一个角色有不一样的【数据规则】,那么设计就变成

      【资源】 - 【主体】 - 【数据规则】

    根据提供者的不同,准备不同的权限应对策略。

    这里可以简单地介绍一下,这个方案至少需要2张表,一个是  【资源,主体,规则关系表】、一个是【数据规则表】

    关系表不能直接保存角色,因为你不确定什么时候业务需要按照【部门】或者【分公司】来定义数据规则

    于是可以用  Master、MasterKey  类似这样的两个字段来确定一个【主体】

    用XML方式的话是这样配置的(放在数据库也类似):

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <settings>
    <rule view="订单" role="销售人员">
    销售员 = {CurrentUserID}
    </rule>
    <rule view="订单" role="总销售经理">
    销售金额 > 100000
    </rule>
    <rule view="订单" role="区域销售经理">
    销售金额 > 100000 and 区域 = {当前用户所属区域}
    </rule>
    </settings>
    复制代码

    对于这种方式有兴趣的朋友也可以试一下,两种方式的【数据规则】是一样的,但是本文没有采用第二种设计方式,因为它多了一层处理逻辑,我以为应该设计越简单越好,就采用第一种方式:

      【资源】 - 【数据规则】

    当然,上面是用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设计通用处理类的文章《 jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载) 》。里面提到的过滤信息是直接的SQL语句。这是不可靠,而且不安全的。
    在前端传输给后台的过滤信息不应该是直接的SQL,而应该是一组过滤规则。在ligerui V1.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] < @p1 and [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] < @p1 and ([CustomerID] = @p2 or [CustomerID] = @p3))
    Parameters:
    p1:2012-01-01
    p2:VINET
    p3:TOMSP
    复制代码

     

    这个过滤规则分为三个部分:【分组】、【规则】(字段、值、操作符)、【操作符】(and or),而自身就是一个分组。
    这种简单的结构就可以满足全部的情况。

    当然,上面提到的这些条件都是在前台定义(可能是用户在搜索框自己输入的)的,而在后台,我们可能会定义一下【隐藏条件】,比如说 【员工只能查看自己的】,要怎么做呢,其实很简单,只需要在后台接收到这个过滤条件(前台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":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
    ],"op":"and"}

     

    ],rules:[{field:'EmployeeID',op:'equal',value:5}]
    }

     

     

    翻译如下:

     

    复制代码
    Text:
    ([EmployeeID] = @p1 and ([OrderDate] < @p2 and ([CustomerID] = @p3 or [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 (SELECT TOP 20 * FROM (SELECT TOP 40 * FROM [Orders] WHERE ( 1=1  and ((@p1 in (@p2,@p3)) or (@p4 = @p5 and [EmployeeID] = @p6))) ORDER BY OrderID ASC) AS tmptableinner ORDER BY OrderID DESC) AS tmptableouter ORDER BY OrderID ASC     
    Parameters:
    @p1[Int32] = 7
    @p2[Int32] = 2
    @p3[Int32] = 6
    @p4[Int32] = 7
    @p5[Int32] = 7
    @p6[Int32] = 1
    复制代码

    {CurrentRuleID} 替换为 7

    {CurrentEmployeeID} 替换为1

     下图是我们设计【数据权限】的界面,可以选择所有的字段,包括几个用户信息:

    这些字段不仅仅只是在文本框中输入值,那么可以自定义数据来源:

     

    复制代码
    var fieldEditors = {};
    fieldEditors['Orders'] = {
    'ShipCity': { type: 'combobox',
    options: {
    width: 200,
    url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"
    }
    }
    };
    复制代码

    效果界面:

     

     

    实际应用

    既然是数据权限控制,如果有一个统一的数据接收入口,我们倒是可以利用这个入口做一些工作。

    比如【ligerRM权限管理系统】统一使用 grid.ashx 这个数据处理程序作为列表数据的接收入口。

    有了统一的接口,方便做权限的控制,使用过 ligerGrid Javascript表格,或者类似插件的朋友,应该比较清楚服务器的交互原理。
    在grid.ashx中,我们会通过
    【视图/表名 】、 【排序信息】、【分页信息】、【过滤信息】
    这几个指标来获取指定的数据。


    而在实际的业务中,可能会引入权限的控制。比如某某【资源】,只能由当前用户自身才能查看,或者只能由当前用户部门及上级部门才能查看。对于这些控制,我们采用对这些可能做权限控制的【资源】注册一组【条件规则】的方式来进行。

     我们将找到view定义好的【数据权限规则】,然后和用户在前台搜索框输入的【搜索规则】合并:

    上面的代码就是数据条件合并的例子,这样便得到了我们最终需要的 过滤规则。

    结语

    本文提出了数据权限的一种实现思路,只是本人在做一个web应用时构思的方案,谈不上规范,欢迎提出你的建议意见。

    可以在http://case.ligerui.com体验实际的应用效果。

    转载于:https://www.cnblogs.com/wangle1001986/p/3241003.html

    展开全文
  • 原型模式

    2019-11-14 14:03:59
    原型模式原型模式(克隆模式/拷贝模式)原型模式实现...-通过new产生一个独享需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 -就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 491
精华内容 196
关键字:

数据权限原型