若依框架改造多租户模式

当前使用版本3.6.4
16.20.2 (Currently using 64-bit executable)
https://doc.ruoyi.vip/ruoyi-cloud/document/hjbs.html

一、若依Cloud改为多租户模式

当前使用版本3.6.4,既然要改为多租户模式,多租户重点是什么,数据隔离,那么我们首先要知道若依是如何做数据隔离。
image.png
查看DataScopeAspect数据过滤处理的方式发现
现在的系统模块是根据deptId去做的权限,可以把部门理解为一个公司,就是一个租户的意思,那么其实我们根据deptId字段就可以实现多租户模式,但毕竟不是那么规范可读性不高,那我们只需要增加tenantId字段赋值deptId即可,后续新增的模块均可使用tenant_id字段进行数据的过滤。
1、通过自定义注解DataScope+AOP的方式 通过部门和角色的关系进行的数据过滤
2、那么我们需要对部门和角色进行数据隔离,在sys_dept和sys_role表中增加tenant_id字段
3、登录赋值tenant_id返回在token,存在每次请求的线程中,便于获取
这样好像是可以的哦,那么部门和角色的多租户是可以完成的,下面的代码是如何增加tenant_id。
那我们把角色放开给租户的管理员,那菜单的权限和角色的数据权限我们怎么处理呢?这个不要急,下面我会讲到
第一步首先增加字段,自行修改实体类和Mapper文件

ALTER TABLE sys_role ADD COLUMN `tenant_id` bigint NOT NULL COMMENT '租户ID';
ALTER TABLE sys_dept ADD COLUMN  `tenant_id` bigint DEFAULT NULL COMMENT '租户ID';

第二步修改DataScopeAspect类的dataScopeFilter()方法
image.png
修改后的代码如下

 public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission){StringBuilder sqlString = new StringBuilder();List<String> conditions = new ArrayList<String>();for (SysRole role : user.getRoles()){String dataScope = role.getDataScope();if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope)){continue;}if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions())&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))){continue;}if (DATA_SCOPE_ALL.equals(dataScope)){sqlString = new StringBuilder();conditions.add(dataScope);break;}else if (DATA_SCOPE_CUSTOM.equals(dataScope)){sqlString.append(StringUtils.format(" OR {}.tenant_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,role.getRoleId()));}else if (DATA_SCOPE_DEPT.equals(dataScope)){sqlString.append(StringUtils.format(" OR {}.tenant_id = {} ", deptAlias, user.getDeptId()));}else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)){sqlString.append(StringUtils.format(" OR {}.tenant_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",deptAlias, user.getDeptId(), user.getDeptId()));}else if (DATA_SCOPE_SELF.equals(dataScope)){if (StringUtils.isNotBlank(userAlias)){sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));}else{// 数据权限为仅本人且没有userAlias别名不查询任何数据sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));}}conditions.add(dataScope);}// 多角色情况下,所有角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据if (StringUtils.isEmpty(conditions)){sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));}if (StringUtils.isNotBlank(sqlString.toString())){Object params = joinPoint.getArgs()[0];if (StringUtils.isNotNull(params) && params instanceof BaseEntity){BaseEntity baseEntity = (BaseEntity) params;baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");}}}

第三步修改sysLoginService.login(查询到当前部门的tenantId返回)和tokenService.createToken代码,其主要目的是讲tenant_id添加在token中

Long tenantId = loginUser.getSysUser().getTenantId();
claimsMap.put(SecurityConstants.DETAILS_TENANT_ID, tenantId);

那我们如何在代码中获取呢
在SecurityUtils类中增加getTenantId方法

public static Long getTenantId()
{return SecurityContextHolder.getTenantId();
}SecurityContextHolder类中添加
public static Long getTenantId()
{return Convert.toLong(get(SecurityConstants.DETAILS_TENANT_ID), 0L);
}
public static void setTenantId(String tenantId) {
set(SecurityConstants.DETAILS_TENANT_ID, tenantId);
}

现在是可以取到了,那在哪里赋值呢在HeaderInterceptor类中这是自定义请求头拦截器,将Header数据封装到线程变量中方便获取,增加代码

SecurityContextHolder.setTenantId(ServletUtils.getHeader(request, SecurityConstants.DETAILS_TENANT_ID));AuthUtil.verifyLoginUserExpire(loginUser);SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser);SecurityContextHolder.set(SecurityConstants.DETAILS_TENANT_ID, loginUser.getSysUser().getTenantId());SecurityContextHolder.set(SecurityConstants.DETAILS_USERNAME, loginUser.getSysUser().getUserName());SecurityContextHolder.set(SecurityConstants.DETAILS_USER_ID, loginUser.getSysUser().getUserId());

那么,目前为止我们已经能根据tenantId来进行租户数据区分了,也可以获取和返回tenantId了
那我们什么时候生成tenantId呢?修改insertDept方法进行赋值即可,也就是新增部门时,将部门的id赋值给tenantId即可。
需要进行权限过滤需要使用该注解。需要自行修改代码,roleService的checkRoleNameUnique,checkRoleKeyUnique。这样是为了使角色独立
image.pngimage.png
根据查看菜单的权限是根据当前角色的权限去拿所以不需要增加tenant也可区分,列如,使用管理员账户增加一个角色,租户管理员角色,配置菜单,这个角色只能配置当前角色下的菜单。
但是每一个租户都有不同的角色分配数据权限时,一定要把全部数据权限禁用掉,不然数据就会串。
image.png
后续增加的业务模块 新增修改查询一定要增加tenantId字段噢。这样就修改完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/24034.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4、后端本地环境搭建

后端本地环境搭建 4.1 安装jdk 下载完成后双击安装的 jdk &#xff0c;点下一步&#xff0c;选择安装目录&#xff0c;一直点下一步&#xff0c;直到结束。 安装完成后同样需要配置环境变量 window s 搜索查看高级系统设置—— 高级 —— 环境变量 —— 系统变量 1、新建一…

java自动化之java基础03-09java基础之数组

数组 1、定义 数组是一种用于存储固定大小的同类型数据的数据结构 1&#xff09;固定大小 2&#xff09;同类型数据的存储 2、声明数组 1&#xff09;数据类型[] 变量名称&#xff1b; 例如&#xff1a;int[] numsArry; 2&#xff09;数据类型 变量名称[]; 例如&#xf…

Linux RS232

一、确认硬件信息 RS232&#xff1a; 引脚信息&#xff1a; 二、软件配置 1、pinctrl信息&#xff1a; 2、设备树节点&#xff1a; 3、修改串口支持的模式 三、驱动 bsp/drivers/uart/sunxi-uart.c 四、烧录测试 查看串口参数&#xff1a; stty -F /dev/ttyAS3 -a stty -F…

TqdmWarning: IProgress not found. Please update jupyter and ipywidgets.

jupyter notebook报错 在pycharm的terminal中 安装完成后就不会再报错了

私有仓库搭建

目前市面上比较常见的私有仓库搭建方法为&#xff1a; 通过 Sinopia 或 verdaccio 搭建&#xff08;Sinopia 已经停止维护&#xff0c;verdaccio 是 Fork 自 Sinopia&#xff0c;基本上大同小异&#xff09;&#xff0c;其优点是搭建简单&#xff0c;不需要其他服务。通过 cnp…

【最新鸿蒙应用开发】——沙箱机制是什么?作用?场景?

沙箱机制 1. 什么是沙箱机制&#xff1f; 1.1. 概念 在操作系统当中&#xff0c;沙箱机制&#xff08;Sandboxing&#xff09;是一种安全机制&#xff0c;用于限制程序代码的访问权限&#xff0c;防止恶意软件对系统造成破坏。在沙箱环境中&#xff0c;程序只能访问特定的资…

动态库加载【Linux】

从此往后&#xff0c;建立映射&#xff0c;我们执行的任何代码&#xff0c;都是在我们的进程地址空间中进行执行 例如&#xff1a;将动态库映射到共享区&#xff0c;进程在CPU调度时&#xff0c;是在进程的进程地址空间处运行 程序在编译好之后&#xff0c;在加载到内存之前&a…

欧美北美南美国外媒体投稿和东南亚中东亚洲媒体海外新闻发稿软文推广营销策略有哪些?

在当今全球化的浪潮中&#xff0c;中国品牌正积极拓展海外市场&#xff0c;寻求更广阔的发展空间。面对国际竞争&#xff0c;有效的海外媒体发稿营销策略对于品牌国际化至关重要。以下是一些关键点和建议&#xff0c;以帮助品牌在海外市场取得成功。 深入了解目标市场&#xf…

Linux 内核之 mmap 内存映射触发的缺页异常 Page Fault

文章目录 前言一、简介1. MMU 内存管理2. 缺页中断3. 页表4. 小节 二、mmap 提前分配物理内存1. mm_populate 函数2. __mm_populate 函数3. populate_vma_page_range 函数4. __get_user_pages 函数5. find_extend_vma 函数6. find_vma 函数7. follow_page_mask 函数8. follow_p…

Ubuntu22.04 下 pybind11 搭建,示例

Pybind11 是一个轻量级的库&#xff0c;用于在 C 中创建 Python 绑定。Ubuntu22下安装pybind11步骤如下&#xff1a; 1. 安装 pybind11 1.1 pip 命令安装 pip3 install pybind11 1.2 源代码安装 安装依赖库&#xff1a; sudo pip install -i https://pypi.tuna.tsinghua.e…

一、Electron 环境初步搭建

新建一个文件夹&#xff0c;然后进行 npm init -y 进行初始化&#xff0c;然后我们在进行 npm i electron --save-dev , 此时我们按照官网的教程进行一个初步的搭建&#xff0c; 1.在 package.json 文件进行修改 {"name": "electron-ui","version…

【全开源】多功能投票小程序系统源码(ThinkPHP+FastAdmin+Uniapp)

&#x1f680; 多功能投票小程序&#xff0c;让决策变得更简单&#xff01; 基于ThinkPHPFastAdminUniapp开发的多功能系统&#xff0c;支持图文投票、自定义选手报名内容、自定义主题色、礼物功能(高级授权)、弹幕功能(高级授权)、会员发布、支持数据库私有化部署&#xff0c…

Java项目如何外发告警日志到企业微信

前言 最近领导交代了一个需求,就是有些许客户不单单满足平台告警日志外发到邮箱、短信的形式,还要以消息聊天的形式外发给企业微信。 具体操作 1、注册企业微信。 2、登录企业微信,找到应用管理,创建应用。 3、创建完之后需要记录以下图片中两个值的信息。 4、然后记录下…

vue实现大语言模型返回的数据将代码高亮显示的实现

0. 引言 最近在学习ai大模型相关的东西&#xff0c;就想着自己做一个类似于chatGPT的网站&#xff0c;做到最后的时候代码块始终是不能高亮显示&#xff0c;以前一直搞Java没太了解过前端vue相关的东西&#xff0c;经过自己查资料&#xff0c;自己慢慢也是研究出来了。 这个项目…

RFID模块板子JY-LD6900通用自由口协议通信说明

RFID模块板子JY-LD6900是健永科技基于RFID无线射频识别技术推出的一款低频读卡模块&#xff0c;体积小巧&#xff0c;性能优越&#xff0c;读卡时间小于30ms&#xff0c;识别速度达2m/s&#xff0c;配套62mm直径圆形天线&#xff0c;读卡距离可达20cm以上。支持双频134.2kHz、1…

分享:618学习狂欢节活动来啦——大数据培训班

618狂欢学习节 限时优惠大放送 活动时间&#xff1a;6月1日—6月18日

商淘云电商分账系统如何为企业降低连锁财务成本

当今激烈的市场竞争中&#xff0c;连锁品牌企业面临着多样化的挑战&#xff0c;其中财务管理尤为关键。商淘云连锁收银系统作为一款专为连锁品牌量身定制的解决方案&#xff0c;不仅可以帮助企业实现总部入账管控财务、银行结算规范财务的目标&#xff0c;还能通过分账系统优化…

什么是SIEM

SIEM 解决方案是一种企业级应用程序&#xff0c;可集中和自动化与网络安全相关的操作&#xff0c;该工具通过收集、分析和关联从组织 IT 基础设施中的各种实体聚合的网络事件来帮助应对网络威胁。 与帮助监控和评估组织物理空间中的危险的监视控制台相比&#xff0c;SIEM解决方…

【漏扫工具】Afrog V3.0.6一款漏洞扫描神器

简介 [Afrog]是一款高性能的漏洞扫描器&#xff0c;快速稳定。它支持用户自定义的 PoC&#xff0c;并内置了多种类型&#xff0c;例如 CVE、CNVD、默认密码、信息泄露、指纹识别、未经授权的访问、任意文件读取和命令执行。借助 afrog&#xff0c;网络安全专业人员可以快速验证…

从一道题看利用sqlite打jdbc达到RCE

前言 从今年国赛的一道java题遇到了sqlite数据库去打jdbc达到RCE的姿势&#xff0c;故笔者写篇文章记下 复现 反编译源代码可以看见这三个数据库 这里提供了mysql sqlite psql 但mysql和psql都不行 这里我们用sqlite去打 jdbc就可以执行load_extension() CVE-2023-32697&#…