MyBatis-Plus演绎:数据权限控制,优雅至极!
🎉🎉欢迎来到我的CSDN主页!🎉🎉
🏅我是尘缘,一个在CSDN分享笔记的博主。📚📚
👉点击这里,就可以查看我的主页啦!👇👇
尘缘的个人主页
🎁如果感觉还不错的话请给我点赞吧!🎁🎁
💖期待你的加入,一起学习,一起进步!💖💖
目录
- 前言
- 1 数据范围
- 2 修改SQL
前言
项目使用mybaits-plus,所以在mybaits-plus的基础上增加数据权限的过滤
mybaits-plus自带数据权限支持,但由于系统数据权限相对复杂,通过查看文档发现好像并不适用,且原项目版本低,所以最终还是通过自己的方式实现
1 数据范围
我们系统相对复杂,比如可以按机构/用户等多种维度过滤,并且可以指定全局和某个特定接口的过滤方式
其实数据范围过滤落地也不过是:数据表的某字段限制在一个范围内,即sql中添加column in (1,2,3...)
不管怎么说第一步都是要获取用户的数据范围,比如某用户的数据范围为机构id为(1,2,3)下的数据,那么先要获取(1,2,3)
首先建立一个类来存储用户的数据范围,由于数据权限是多维度的,所以存储的是一个Map<String, List<String>>
结构
public class GerneralScope extends HashMap<String, List<String>> {
}
存储的数据类似如下
{"org_id": [1,2,3], // 机构id"user_id": [], // 为空代表不过滤用户id"xxx_id": [4,8] // 其它为敌
}
使用ThreadLocal进行暂存,并在拼接sql时使用,这样可以避免代码侵入
public class ScopeDataHolder {public final static ThreadLocal<GerneralScope> SCOPE_DATA = new ThreadLocal<>();public static GerneralScope get() {GerneralScope gerneralScope = SCOPE_DATA.get();SCOPE_DATA.remove(); // 获取一次就删除return gerneralScope;}public static void set(GerneralScope data) {SCOPE_DATA.set(data);}
}
数据结构准备好了,接下来就是获取当前用户数据范围存入ScopeDataHolder,采用注解+AOP的方式避免代码侵入
新增注解@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Scope {ApiType value() default ApiType.COMMON;
}
其中加一个参数value用来区分不同接口,即可实现特定接口单独过滤方式
AOP获取并设置数据范围
@Component
public class ScopeAspect {@Pointcut("@annotation(com.xxx.Scope)")public void injectScope() {}/*** 注入数据权限* @param joinPoint* @return*/@Before("injectScope()")public void around(JoinPoint joinPoint) {Scope annotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(Scope.class);GerneralScope userScopeData = getCurrentUserScopeData(annotation.value()); // 数据库获取当前用户+当前接口的数据范围ScopeDataHolder.set(userScopeData); // 存入ThreadLocal}
}
到此,零侵入代码情况下,通过ThreadLocal暂存了用户所配的数据范围
2 修改SQL
获取到了用户的数据范围,下一步就是在查询中加入数据范围的过滤,即修改sql
刚开始本来打算用mybaits-plus的自定义拦截器实现sql的修改,后来发现有很多坑,主要是当sql中存在left join且分页时,mybaits-plus的分页器在count查询时自动把没有查询条件的left join表去掉,如果限定数据范围的字段刚好在join表上,就会导致错误
所以最终没有采用拦截器,而是采取重写mybaits-plus的QueryWrapper
类来实现,代码如下
public class ScopeQueryWrapper<T> extends QueryWrapper<T> {private final GerneralScope queryScope;public ScopeQueryWrapper() {this.queryScope = ScopeDataHolder.get(); // 从ThreadLocal获取数据范围if (this.queryScope==null) {throw new IllegalStateException();}}/*** 过滤需要筛选的字段* @param column*/@SuppressWarnings("unchecked")public void scope(ScopeEnum type, SFunction<T, ?> column) {List<String> els = queryScope.get(type.getValue());if (els!=null && els.size()!=0) {lambda().in(column, els);}}/*** 过滤需要筛选的字段* @param fieldName*/@SuppressWarnings("unchecked")public void scope(ScopeEnum type, String fieldName) {List<String> els = queryScope.get(type.getValue());if (els!=null && els.size()!=0) {in(fieldName, els);}}
}
这样只需在查询层把QueryWrapper替换为ScopeQueryWrapper
,并使用scopeFilter方法来指定界限字段即可,写法如下
public Page<User> page(UserQuery query) {Page<User> page = new Page<>(query.getPageNum(), query.getPageSize());ScopeQueryWrapper<User> wrapper = new ScopeQueryWrapper<>();if (query.getName()!=null) {wrapper.lambda().like(User::getName,query.getName());}/** 数据权限 start **/wrapper.scope(ScopeEnum.orgId, User:getOrgId); // 指定机构id字段wrapper.scope(ScopeEnum.userId, "user.id"); // 指定用户id字段,字符串方式可以防止join字段重名...省略其它过滤条件/** 数据权限 end**/wrapper.lambda().orderByDesc(User::getId);Page<User> result = page(page, wrapper);return result;
}
如上,需要指定具体需要过滤的字段,由于是多维度,可能会指定很多,ScopeEnum
即各维度的枚举,scope方法中的getValue获取到的即用户设置范围数据的key
ScopeEnum
scope
接受字符串形式,可以避免join时字段有歧义
以上代码出现了代码的侵入,但自认为可以接受,如果不需要多维度可以进一步简略
最终,执行的sql大体如下
select * from user where name like "%pq%" and org_id in (1,2,3) and user.id in (4,8,10)
💖如果觉得有用的话还请点个赞吧 💖
相关文章:
MyBatis-Plus演绎:数据权限控制,优雅至极!
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是尘缘,一个在CSDN分享笔记的博主。📚📚 👉点击这里,就可以查看我的主页啦!👇&#x…...
医学专题--多组学在药物治疗靶点筛选中的研究思路
研究背景 药物靶点(drug target):是指药物在体内的作用结合位点,包括基因位点、受体、酶、离子通路、核酸等生物大分子,靶向药物从单靶点药物到多靶点药物都在不断进行临床探索。小分子多靶点药物因其多靶向性、高效率…...
搜索与图论总结
算法博文DFSDFS(深度优先)-CSDN博客BFSBFS(宽度优先)(最短路)-CSDN博客有向图与无向图有向图与无向图(邻接表)_无向图有向图邻接表_人生导师yxc的博客-CSDN博客拓扑排序topsort(拓扑排序)-CSDN博客最短路最…...
lv8 嵌入式开发-网络编程开发 15I/O多路复用及select函数
目录 1 I/O多路复用 1.1 select函数及其他接口相关介绍 1.2 原TCP—socket示例: 1.3 实现select函数TCP—socket示例: 2 练习 1 I/O多路复用 多路复用的实现方式 1.1 select函数及其他接口相关介绍 int select(int nfds, fd_set *readfds, fd_set…...
阿里云 linux tomcat 无法访问方法
1、阿里云放行tomcat端口 例如7077端口号 2、linux 命令行防火墙 设置端口打开 以下命令查看是否开启指定端口 firewall-cmd --list-ports以下命令添加指定端口让防火墙放行 firewall-cmd --zonepublic --add-port3306/tcp --permanent以下命令重新启动防火墙 systemctl re…...
公园视频监控系统如何改造?人工智能又能提供哪些帮助?
近日合肥市骆岗公园宣布正式开园,作为目前世界最大的城市公园,占地12.7万平方公里,如此壮观宏伟的建设,也吸引到了不少市民进行参观打卡。不管大型小型,城市里的公园都是随处可见的,那么,公园安…...
面试算法19:最多删除一个字符得到回文
题目 给定一个字符串,请判断如果最多从字符串中删除一个字符能不能得到一个回文字符串。例如,如果输入字符串"abca",由于删除字符’b’或’c’就能得到一个回文字符串,因此输出为true。 分析 本题还是从字符串的两端…...
H5+Css3文本溢出添加省略号(包括插件)
一、单行 溢出隐藏 添加省略号 p{overflow: hidden;text-overflow:ellipsis;white-space: nowrap; }二、多行 溢出隐藏 省略号 p{display: -webkit-box;-webkit-box-orient: vertical;/*设置省略号在容器第四行文本后*/-webkit-line-clamp: 4; overflow: hidden; }局限性&…...
将休眠镜像文件hiberfil.sys移动到D盘,可以减少C盘好几个G的空间占用
hiberfil.sys是什么文件? 该文件是开启休眠功能后,系统自动生成的内存镜像文件,以便我们唤醒电脑之后可以快速开启程序。 1、首先打开电脑,使用“windowsR”组合键进入运行,输入“regedit”命令。 2、在注册表编辑器中…...
YTM32的模数转换器ADC外设模块详解
文章目录 简介原理与机制ADC转换器的上下电和省电模式ADC转换结果和FIFOADC转换队列的工作模式ADC转换器的触发信号ADC转换器的看门狗中断事件和DMA 应用要点(软件)总结参考文献 简介 YTM32的ADC转换器外设最多可以集成32个输入通道,最高12b…...
前端vue学习笔记——Vuex
1.概念 在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。 2.何时使用?…...
7个在Github上的flutter开源程序
阅读大量代码是提高开发技能的最佳方法之一。该开源项目是了解最佳实践、编码风格和许多其他主题的最佳场所。 软件开发最受欢迎的领域之一是跨平台移动应用程序开发。Flutter 是您可以使用的最流行的跨平台移动应用程序开发工具之一。今天,我们将了解 7 个开源 Flu…...
计算机基础
分值:3-7 1. 计算机系统概述 2. 计算机组成结构 3. 存储结构 3.1. 层次化存储结构 一般用什么调什么,局部性原理 内存和外存可以统称为虚拟存储器 我们可以操作哪些:操作外存、内存、CPU寄存器。Cache具有透明性。 3.2. Cache Cache的功…...
Oracle-ASM实例communication error问题处理
问题背景: Oracle数据库日志出现大量的WARNING: ASM communication error: op 0 state 0x0 (15055)错误 问题分析: 首先检查ASM实例的状态,尝试通过sqlplus / as sysasm连接asm实例,出现Connected to an idle instance连接asm实例失败 检查ASM实例的后台…...
gin路由相关方法
c.Request.URL.Path 拿到请求的路径 package mainimport ( "fmt" "github.com/gin-gonic/gin" "net/http")//路由重定向,请求转发,ANY ,NoRoute,路由组func main() { r : gin.Default() // -------…...
vue项目 Editor.md使用示例
简介 Editor.md 支持“标准” Markdown / CommonMark 和 Github 风格的语法,也可变身为代码编辑器; 支持实时预览、图片(跨域)上传、预格式文本/代码/表格插入、代码折叠、搜索替换、只读模式、自定义样式主题和多语言语法高亮等…...
12.3 实现模拟鼠标录制回放
本节将向读者介绍如何使用键盘鼠标操控模拟技术,键盘鼠标操控模拟技术是一种非常实用的技术,可以自动化执行一些重复性的任务,提高工作效率,在Windows系统下,通过使用各种键盘鼠标控制函数实现动态捕捉和模拟特定功能的…...
【计算机网络-自顶向下方法】应用层(SMTP、POP3、DNS)
目录 1. Electronic Mail电子邮件应用画像1.1 电子邮件系统1.2 邮件报文格式1.3 邮件访问 2. DNS(Domain Name System)2.1 DNS提供的服务2.2 DNS工作机理2.3 DNS资源记录2.4 DNS协议,报文2.5 小结 1. Electronic Mail 电子邮件应用画像 应用…...
【Pm4py第八讲】关于Statistics
本节用于介绍pm4py中的统计函数,包括统计轨迹变体、案例持续时间、案例到达时间等。 1.函数概述 本次主要介绍Pm4py中一些常见的统计函数,总览如下表: 函数名说明pm4py.stats.get_start_activities()从事件日志中获取开始活动。pm4py.stats.…...
【Azure 架构师学习笔记】-Azure Data Factory (5) --Data Flow
本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Data Factory】系列。 接上文【Azure 架构师学习笔记】-Azure Data Factory (4)-触发器详解-事件触发器 前言 Azure Data Factory, ADF 是微软Azure 的ETL 首选服务之一, 是Azure data platfor…...
uniapp之ios开发及支付整体流程爬坑记录
前言 在写这篇记录的时候,关于ios的支付已经对接的差不多了,下一步就是测试好了直接发版,总共花了好几周的时间,从0到1对于首次做ios支付来说,确实很多坑。 其实业务层面很简单,甚至比安卓支付还简单&…...
AutoDL百川大模型体验
文章目录 镜像克隆模型下载测试效果AutoDL自定义服务 感谢AutoDL和CodeWithGPU这两个平台,让我们能低成本,低门槛地部署体验这些大模型 镜像克隆 我是在CodeWithGPU上克隆的这个镜像 模型下载 codewithgpu有介绍 注意这三个文件都需要下载 把那个&quo…...
蓝桥杯每日一题2023.10.8
题目描述 七段码 - 蓝桥云课 (lanqiao.cn) 题目分析 所有的情况我们可以分析出来一共有2的7次方-1种,因为每一个二极管都有选择和不选择两种情况,有7个二极管,但是还有一种都不选的情况需要排除,故-1 枚举每个方案看是否符合要…...
jmeter,性能测试,Locust
一。性能测试的概念 1.性能:就是软件质量属性中的 “ 效率 ” 特性 2.效率特性: 时间特性:指系统处理用户请求的响应时间 资源特性:指系统在运行过程中,系统资源的消耗情况 CPU 内存 磁盘IO(磁盘的写…...
opencv图像的直方图,二维直方图,直方图均衡化
文章目录 opencv图像的直方图,二维直方图,直方图均衡化一、图像的直方图1、什么是图像的直方图:2、直方图的作用:3、如何绘制图像的直方图:(1)cv::calcHist()函数原型:英文单词 calc…...
c++中的map和set
文章目录 1. 关联式容器2. 键值对3. 树形结构的关联式容器3.1 set3.1.1 set的介绍3.1.2 set的使用 3.2 map3.2.1 map的介绍3.2.2 map的使用 3.3 multiset3.3.1 multiset的介绍3.3.2 multiset的使用 3.4 multimap3.4.1 multimap的介绍3.4.2 multimap的使用 1. 关联式容器 在初阶…...
Swagger使用详解
目录 一、简介 二、SwaggerTest项目搭建 1. pom.xml 2. entity类 3. controller层 三、基本使用 1. 导入相关依赖 2. 编写配置文件 2.1 配置基本信息 2.2 配置接口信息 2.3 配置分组信息 2.3.1 分组名修改 2.3.2 设置多个分组 四、常用注解使用 1. ApiModel 2.A…...
ToBeWritten之车联网安全中常见的TOP 10漏洞
也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 转移发布平台通知:将不再在CSDN博客发布新文章,敬…...
软考-密码学概述
本文为作者学习文章,按作者习惯写成,如有错误或需要追加内容请留言(不喜勿喷) 本文为追加文章,后期慢慢追加 by 2023年10月 密码学基本概念 密码学的主要目的是保持明文的秘密以防止攻击者获知,而密码分…...
windows 2003、2008远程直接关闭远程后设置自动注销会话
1、2003系统: 按开始—运行—输入“tscc.msc”,打开“终端服务配置”。 单击左边窗口的“连接”项,右边窗口中右击“RDP-TCP”,选择“属性”。 单击“会话”项,勾选“替代用户设置”,在“结束已断开的会话”…...
wordpress系统付费/软文代写平台
Unity 3D 是目前主流的游戏开发引擎,有数据显示,全球最赚钱的 1000 款手机游戏中,有 30% 是使用 Unity 3D 开发出来的。尤其在 VR 设备中,Unity 3D 游戏开发引擎具有统治地位。 Unity 3D 能够创建实时、可视化的 2D 和 3D 动画、…...
关键词是在网站后台做的吗/深圳市住房和建设局
北京各街头的情愿 今天是2016年10月24日,也是1024程序员节,就在前几天,作为IT人群高密度聚集的北京地区,在北京各个街头出现了大量参与“程序员不加班”的请愿行动的人群,受北京“1024程序员节”请愿活动影响ÿ…...
随州网站推广/网站关键词排名优化客服
下面是一个检查对象是否为空的代码片段。对于新的浏览器而言,你可以使用普通的 JS 和 ES6 的语法 Object.keys。但是,为了支持旧的浏览器,你可以安装 Lodash 和使用它的 isEmpty 方法。const empty {};/* -------------------------针对新浏…...
docker 部署wordpress/男生技能培训班有哪些
之前已经说了前面八个问题,现在接着往下分享,没有看到之前的文章的可以点击这里哦~ 九、Swoole如何正确的重启服务 在我们修改了 PHP 代码后经常需要重启服务让代码生效,一台繁忙的后端服务器随时都在处理请求,如果管理员通过 k…...
新网站不被收录/电商网站大全
文章目录React 简介React 概述及特点React 虚拟DOMReact 渲染机制React 基本使用JSX 语法createElement()方法深究JSX语法规则React 简介 React 概述及特点 是一个用于构建用户界面,将数据渲染为HTML视图的开源 JavaScript库 中文官网:React官方中文文档…...
资阳的网站建设/seo的目的是什么
参考资料: 基于Qt的P2P局域网聊天及文件传送软件设计 http://bbs.csdn.net/topics/390386771 分享qtffmpegsdl播放视频。 ffmpeg各种项目 https://trac.ffmpeg.org/wiki/Projects http://blog.sina.com.cn/s/blog_554f7c9501015vqx.html 用qt开发ffmpeg应用gui。…...