数据权限设计——基于EntityFramework的数据权限设计方案:一种设计思路

简介:

一、大话权限模块

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

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

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

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

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

二、一种设计思路

关于权限设计的杂谈就告一段落,凡是点到即止,再说了多了就说烂了。到目前为止,博主找到的一篇写得相对比较好的文章 通用权限管理设计 之 数据权限。这位博主是用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(1))
            {
                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("1", 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/p/7760803.html,如需转载请自行联系原作者


目录
相关文章
|
JavaScript 前端开发 开发工具
使用Vue.js、Vuetify和Netlify构建现代化的响应式网站
使用Vue.js、Vuetify和Netlify构建现代化的响应式网站
370 0
|
敏捷开发 存储 搜索推荐
《阿里巴巴Java开发手册v1.4.0(详尽版)》更新,新增16条设计规约
阿里巴巴集团推出的《阿里巴巴Java开发手册》是阿里巴巴近万名开发同学集体智慧的结晶,以开发视角为中心,详细列举如何开发更加高效、更加容错、更加有协作性,力求知其然,更知其不然,结合正反例,让Java开发者能够提升协作效率、提高代码质量。
737757 3
|
SQL 存储 数据安全/隐私保护
MyBatis-Plus演绎:数据权限控制,优雅至极!
项目使用mybaits-plus,所以在mybaits-plus的基础上增加数据权限的过滤 mybaits-plus自带数据权限支持,但由于系统数据权限相对复杂,通过查看文档发现好像并不适用,且原项目版本低,所以最终还是通过自己的方式实现
1720 1
MyBatis-Plus演绎:数据权限控制,优雅至极!
|
Kubernetes 负载均衡 应用服务中间件
部署Kubernetes(k8s)多主的高可用集群
在CentOS7上安装Kubernetes多主节点的集群,并且安装calico网络插件和metallb。使用keepalived和haproxy进行负载均衡。最后部署应用
4284 0
|
消息中间件 Kafka Go
module declares its path as: github.com/IBM/sarama but was required as: gith
module declares its path as: github.com/IBM/sarama but was required as: gith
|
Web App开发 Rust 前端开发
【一起学Rust | 框架篇 | Tauri2.0框架】Tauri App开启远程调试功能
【一起学Rust | 框架篇 | Tauri2.0框架】Tauri App开启远程调试功能
1093 0
|
SQL 存储
数据权限就该这么实现(实践篇),yyds!
数据权限就该这么实现(实践篇),yyds!
994 0
|
机器学习/深度学习 敏捷开发 人工智能
现代软件测试技术的演进与应用
随着软件行业的快速发展,软件测试技术也在不断演进和创新。本文探讨了现代软件测试技术的最新趋势和应用,包括自动化测试、持续集成与持续交付、AI在测试中的应用等方面。通过分析这些技术的发展,我们可以更好地理解如何提高软件质量、加速交付,并提升开发团队的效率和创新能力。 【7月更文挑战第10天】
282 3
|
SQL 存储 数据库
flink sqlserver cdc实时同步(含sqlserver安装配置等)
超详细讲解flink sqlserver cdc实时同步(含sqlserver安装配置等)
1212 0
flink sqlserver cdc实时同步(含sqlserver安装配置等)
|
SQL 缓存 开发框架
SpringCloud微服务实战——搭建企业级开发框架(二十八):扩展MybatisPlus插件DataPermissionInterceptor实现数据权限控制
一套完整的系统权限需要支持功能权限和数据权限,前面介绍了系统通过RBAC的权限模型来实现功能的权限控制,这里我们来介绍,通过扩展Mybatis-Plus的插件DataPermissionInterceptor实现数据权限控制。   简单介绍一下,所谓功能权限,顾名思义是指用户在系统中拥有对哪些功能操作的权限控制,而数据权限是指用户在系统中能够访问哪些数据的权限控制,数据权限又分为行级数据权限和列级数据权限。
1845 27
SpringCloud微服务实战——搭建企业级开发框架(二十八):扩展MybatisPlus插件DataPermissionInterceptor实现数据权限控制