前言:“我们有一个订单列表,希望能够根据当前登陆的不同用户看到不同类型的订单数据”、“我们希望不同的用户能看到不同时间段的扫描报表数据”、“我们系统需要不同用户查看不同的生产报表列”。诸如此类,最近经常收到项目上面的客户提出的这种问题,即所谓的“数据权限”,经过开会讨论决定:在目前的开发框架上面搭建一套通用的数据权限功能。

本文原创地址:http://www.cnblogs.com/landeanfen/p/7760803.html

一、大话权限模块

有了上面的引言,自然而然就引出了今天需要和大家讨论的话题——数据权限。作为开发人员,我们肯定知道,一般的系统都离不开权限模块,它是支撑整个系统运行的基础模块。而根据项目类型和需求的不同,权限模块的设计更是大相径庭。但不管怎么变,权限模块从大的方面来说,可以分为两种大的类型:功能权限数据权限

  • 功能权限:主要控制不同的资源主体(用户、角色、组织等)有操作不同的资源的权限。比如常见的不同的角色能访问不同的页面(菜单权限),以及具有操作同一页面的不同功能(按钮权限)等等,都数据功能权限的范畴,这种设计相对比较简单,也比较为大多数系统所通用。当然网上资料、设计思路也可以找到很多。
  • 数据权限:主要控制不同的资源主体(用户、角色、组织等)有查看不同的数据信息的权限,一般来说,数据权限又分为数据行权限数据列权限,通过字面意思不难理解这两者的区别,比如上文“我们有一个订单列表,希望能够根据当前登陆的不同用户看到不同类型的订单数据” 这就是一个典型的数据行权限,而“我们系统需要不同用户查看不同的生产报表列”这就是数据列权限的范畴。由于数据权限和系统的业务逻辑关系非常密切,所以不同的系统设计差异性会非常大。从另一方面来说,由于数据权限和业务逻辑关联性非常强,如果系统的业务逻辑非常复杂,数据权限设计起来也会相对复杂,所以关于数据权限的设计一直没有一种相对通用和使用简单的设计方案。

如果你动手去设计数据权限,当你去各大平台、百度、谷歌查找设计思路的时候,你会发现很难找到有用的资料,很多设计思路局限性非常大。其实原因很简单:数据权限的设计和他人系统关系紧密,一般不太容易拿到你的项目上面直接使用。

当然也有另外部分人说“数据权限并不能作为权限模块去设计”,比如博主看到这样一条评论

从一定程度上来说,这样理解也不为过,如果你觉得你的系统灵活性和配置性不需要那么高,把数据权限的规则在代码里面写死又何妨,博主所在公司的另外一个部门就是这么干的,除了编码量大一点,其实也没什么太大的问题!其实博主说这么多无非是想表达一个观点:没有绝对通用的数据权限设计思路,关键看合不合你用!当然本文的设计思路也是一样,不强制要求,不提通用。设计思路供你参考!

二、一种设计思路

关于权限设计的杂谈就告一段落,凡是点到即止,再说了多了就说烂了。到目前为止,博主找到的一篇写得相对比较好的文章 通用权限管理设计 之 数据权限。这位博主是用sql去实现的,如果是把这个运用到EF里面的话,考虑到EF复杂的导航属性,会有一些问题。接下来说说博主这边想到的设计思路。

先说说博主所在项目的情况,和数据打交道的部分采用EntityFramework+Repository的传统模式去实现的,整个项目从上到下,就是一种典型的"伪DDD",什么是”伪DDD“?这里不做过多说明,使用过DDD的同仁应该很清楚。下面是设计思路流程图:

第一步:配置数据规则

第二步:页面使用数据规则

以上是一个大致的思路图,总的来说,要实现基于EF的数据权限设计,主要分为两大步骤

1、配置数据规则

配置数据规则这里有三个大的方面:功能模块数据资源角色

  • 功能模块:为什么这里要加上功能模块的约束?是因为博主觉得我们某一个页面在查询数据的时候,会有一个查询的范围,比如订单查询页面肯定只能查询和订单有关联的实体功能,而不可能查询和它没有任何关联的业务。加这个约束更大的意义在于我们动态的构造Lambda去查询实体的时候不会产生”找不到相关联的实体“之类的错误
  • 数据资源:具体对哪种数据资源做数据权限,比如订单的状态不等于取消状态、订单的下单时间小于当前月份等等。
  • 角色:数据资源的主体,还可以是用户、部门、组织等等。

这三者配置之后得到的一个结果就是某一类角色的某一个功能模块对哪个数据资源的数据规则是什么样的。比如有一条销售总监的数据规则,配置销售总监在订单模块里面订单这个实体的订单类型是销售订单的所有数据,这就是针对销售总监在订单模块的数据规则。可能最终数据库存储得到的数据类似这样:

RoleId FunctionCode Rules
2 OrderQuery

{"rules":[{"field":"Order_Status","operate":"in","value":"[0,1,2]"},{"field":"Order_Type","op":"equal","value":"1"}],"logicoperate":"and"}

3 OrderQuery

{"rules":[{"field":"Order_Status","operate":"in","value":"[0]"},{"field":"Product.Categary.Type","equal":"equal","value":"1"}],"logicoperate":"and"}

5 Product

{"groups":[

{"rules":[{"field":"Order_Status","operate":"in","value":"[0,5,10]"},{"field":"Order_Type","op":"equal","value":"1 "}],"logicoperate":"and"},

{"rules":[{"field":"LineName","operate":"equal","value":"fenzhuangxian"}]}

],"logicoperate":"or"}

需要特别说明的是:由于EF有导航属性,这里的Rules在保存的时候如果遇到导航属性,我们的字段值需要这样保存——Product.Categary.Type。因为在我们转换成为lambda表达式的时候导航属性会是这样写:x=>x.Product.Categary.Type==1。这个我们在后面使用这个规则的时候加以说明。

2、使用数据规则

有了上面的数据规则,接下来就是我们在取数据的时候如何使用了,这里有一点需要说明的是:我们这里需要传两个参数,一个是模块的名称,比如上面的OrderQuery、Product等;第二个是当前用户的角色id,这个可以通过当前登陆用户的id获取到角色。

要使用数据规则,之前博主分享过两篇关于动态Lambda的文章,现在派上用场了。只不过原来只是一些基础类型转lambda,现在涉及到了导航属性,不知道是否可行。博主查阅了一些资料,最终找到了解决方案。

     //遍历得到属性(包括遍历导航属性)
public Expression GetProperty(Expression source, ParameterExpression para, string Name)
{
string[] propertys = Name.Split('.');
if (source == null)
{
source = Expression.Property(para, typeof(Entity).GetProperty(propertys.First()));
}
else
{
source = Expression.Property(source, propertys.First());
}
foreach (var item in propertys.Skip())
{
source = GetProperty(source, para, item);
}
return source;
}

然后测试如下

            var oLamadaExtention = new LambdaExpression<Order>();
var left = oLamadaExtention.GetProperty(null, Expression.Parameter(typeof(Order), "x"), "Product.Categary.Type");
var value = Expression.Constant("", left.Type);
//动态转换类型
var right = Expression.Constant(value, left.Type);
Expression expRes = Expression.Equal(left, right);

测试得到的查询lambda结果为x=>x.Product.Categary.Type=="1",测试成功!

3、补充一点

对于配置数据规则的时候还有一点比较麻烦的是,如果如何知道哪个功能模块使用哪些实体?不可能直接让用户去写Product.Categary.Type这些复杂的功能吧,如果是这样,谈何体验。那么只有使用另外一种解决思路了——反射EF实体。

反射EF实体的时候如果是导航属性,还得继续反射导航属性的实体,这样一层一层反射下去,最终确实是可以得到形如Product.Categary.Type这个的结构体,但界面如何展现还有待思考。比如思路如下:

三、总结

以上只是一个设计思路,理论上来说是可以实现的,如有不足,欢迎斧正,谢谢。如果思路没有问题,后续博主会抽时间将这种设计的实现过程展现出来供大家参考,欢迎关注。其中的难点有两个:

1、逐级反射EF的导航属性,以及这个过程如何展现。是通过特性标记,还是开发人员配置;

2、动态Expression在构造Lambda的时候和配置数据的兼容性问题,比如数据类型的兼容性有点难控制。

本文原创出处:http://www.cnblogs.com/landeanfen/

欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利

数据权限设计——基于EntityFramework的数据权限设计方案:一种设计思路的更多相关文章

  1. Creating adaptive web recommendation system based on user behavior(设计基于用户行为数据的适应性网络推荐系统)

    文章介绍了一个基于用户行为数据的推荐系统的实现步骤和方法.系统的核心是专家系统,它会根据一定的策略计算所有物品的相关度,并且将相关度最高的物品序列推送给用户.计算相关度的策略分为两部分,第一部分是针对 ...

  2. 基于 DolphinScheduler 的数据质量检查实践

    今天给大家带来的分享是基于 Apache DolphinScheduler 的数据质量检查实践,分享的内容主要为以下四点: " 为什么要做数据质量检查? 为什么要基于 DolphinSche ...

  3. 基于EntityFramework的权限的配置和验证

    1.   概要 本文主要介绍公司现有系统框架的权限体系,和一些待扩展功能的说明.目前该权限体系基于角色构建(RBAC),原则上,系统中不允许出现对用户.组织等其他对象指派权限的情况. 2.   权限分 ...

  4. 基于RBAC模型的权限设计:如何设计系统权限体系?

    一.什么是RABC RBAC(基于角色的权限控制)模型的核心是在用户和权限之间引入了角色的概念.取消了用户和权限的直接关联,改为通过用户关联角色.角色关联权限的方法来间接地赋予用户权限(如下图),从而 ...

  5. 一个基于RBAC0的通用权限设计清单

    注:RBAC0与RBAC1不同在于权限继承.关于RBAC1的权限设计,敬请关注作者后续CSDN博客.1,用户表 保存系统用户信息,如张三.李四,字段可以有id.name.fullname.email. ...

  6. Transform开发cube模型权限处理之不同用户数据的过滤

    ========================此文不再详细的说transform的开发过程====================================================== ...

  7. SpringSecurity权限管理系统实战—九、数据权限的配置

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  8. Smartbi权限安全管理系统_保障数据权限安全

    思迈特软件Smartbi具有完善的安全管理体系,Smartbi权限安全管理系统它可以控制用户功能权限.数据访问权限.资源访问权限.Smartbi权限安全管理系统支持按用户.用户组.角色进行管理:支持多 ...

  9. 【Java EE 学习 76 上】【数据采集系统第八天】【角色授权】【用户授权】【权限的粗粒度控制】【权限的细粒度控制】

    一.角色管理 单击导航栏上的"角色管理"超链接,跳转到角色管理界面,在该界面上显示所有角色,并提供角色的增加和删除.修改超链接. 1.增加新角色(角色授权) 流程:单击增加新角色超 ...

随机推荐

  1. Python学习笔记008_类_对象_继承_组合_类相关的BIF

    # 对象 = 属性 + 方法>>> # Python中的类名约定以大写字母开始>>> # tt = Turtle() 这就是创建类实例的方法,其它语言用new ,它 ...

  2. 配置exVim开发环境

    exVim主页 http://exvim.github.io/ 使用该配置原因: 简单,组织各种优秀插件,安装包很小,各种操作很流畅 实用,对于项目来说,只需要多出一个xx.exvim文件,所有符号等 ...

  3. 【Linux笔记(001) 】-- centos7 系统目录结构与文件

    一.目录结构与用途: /boot:系统引导文件.内核 /bin:用户的基本命令 /dev:设备文件 /etc:配置文件 /home:用户目录 /root:root用户目录 /sbin:管理类的基本命令 ...

  4. pdf点击超链接后返回:alt+ 向左 /向右

    pdf点击超链接后返回:alt+ 向左 /向右

  5. Hive任务优化(2)

    JOIN优化 1.大多数情况下,Hive会对每对Join连接对象启动一个MapReduce任务. 2.多表关联时,如果每个ON子句都使用相同的连接键的话,那么只会产生一个MapReduce Job. ...

  6. Linux脚本入门(1)

    1. Linux 脚本编写基础1.1 语法基本介绍1.1.1 开头程序必须以下面的行开始(必须方在文件的第一行): #!/bin/sh 符号#!用来告诉系统它后面的参数是用来执行该文件的程序.在这个例 ...

  7. Hive基础(4)---Hive的内置服务

    版权声明:<—— 本文为作者呕心沥血打造,若要转载,请注明出处@http://blog.csdn.net/gamer_gyt <——   目录(?)[+]   一:Hive的几种内置服务 ...

  8. [spring 入门第一天]

    关于Spring Framework 简介: Spring框架提供了一个全面的现代java企业应用程序编程和配置模型——可以部署在任何类型的平台.支持任何级别的应用程序:spring专注于程序架构,这 ...

  9. HDU 5976 数学

    Detachment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  10. Judge Route Circle

    Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot m ...