若依框架修改为多租户

若依框架自带了 Spring Security 权限管理,但没有原生支持多租户,目前的需求就是改为多租户的形式

若依框架修改为多租户

  • 前端部分
    • 1. 登录页面
      • 1.1 新增租户选择项
    • 3. 菜单和权限处理
      • 3.1 根据租户动态加载菜单
    • 4. 数据展示和操作
      • 4.1 处理不同租户的数据
    • 5. 全局状态管理
      • 5.1 存储租户信息
  • 后端部分
    • 1. 多租户实现思路
    • 2. 数据库设计修改
      • 2.1 新增租户表
    • 2.2 修改用户表
    • 3. 请求层面处理
      • 3.1 拦截请求获取租户标识
      • 3.2 租户上下文工具类
    • 4. 权限层面处理
      • 4.1 修改 Spring Security 配置
      • 4.2 修改权限验证逻辑
    • 5. 数据访问层面处理
    • 6. 配置拦截器或过滤器

前端部分

1. 登录页面

1.1 新增租户选择项

在登录页面添加一个租户选择框,让用户在登录时选择所属的租户。可以从后端获取租户列表,填充到选择框中。

<template>
  <div>
    <!-- 用户名输入框 -->
    <el-input v-model="username" placeholder="请输入用户名"></el-input>
    <!-- 密码输入框 -->
    <el-input v-model="password" type="password" placeholder="请输入密码"></el-input>
    <!-- 租户选择框 -->
    <el-select v-model="tenantId" placeholder="请选择租户">
      <el-option
        v-for="tenant in tenantList"
        :key="tenant.tenantId"
        :label="tenant.tenantName"
        :value="tenant.tenantId">
      </el-option>
    </el-select>
    <!-- 登录按钮 -->
    <el-button @click="login">登录</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: '',
      password: '',
      tenantId: null,
      tenantList: []
    };
  },
  created() {
    // 获取租户列表
    this.getTenantList();
  },
  methods: {
    getTenantList() {
      // 调用后端接口获取租户列表
      this.$axios.get('/api/tenant/list').then(response => {
        this.tenantList = response.data;
      });
    },
    login() {
      // 登录请求,携带租户 ID
      this.$axios.post('/api/login', {
        username: this.username,
        password: this.password,
        tenantId: this.tenantId
      }).then(response => {
        // 处理登录成功逻辑
      });
    }
  }
};
</script>
  1. 请求拦截器
    2.1 添加租户信息到请求头
    在前端的请求拦截器中,将当前租户 ID 添加到请求头中,以便后端能够识别请求所属的租户。
import axios from 'axios';

// 创建 axios 实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
});

// 请求拦截器
service.interceptors.request.use(
  config => {
    // 获取当前租户 ID
    const tenantId = localStorage.getItem('tenantId');
    if (tenantId) {
      // 将租户 ID 添加到请求头
      config.headers['X-Tenant-ID'] = tenantId;
    }
    return config;
  },
  error => {
    console.log(error);
    Promise.reject(error);
  }
);

export default service;

3. 菜单和权限处理

3.1 根据租户动态加载菜单

不同租户可能有不同的菜单和权限,前端需要根据当前租户动态加载菜单。可以在登录成功后,根据租户 ID 请求后端获取该租户的菜单信息。

// 登录成功后,获取当前租户的菜单信息
this.$axios.get('/api/menu/list', {
  params: {
    tenantId: this.tenantId
  }
}).then(response => {
  // 动态生成菜单
  this.menuList = response.data;
});

4. 数据展示和操作

4.1 处理不同租户的数据

在展示和操作数据时,前端需要确保只显示和操作当前租户的数据。可以在请求数据时,将租户 ID 作为参数传递给后端,后端根据租户 ID 进行数据过滤。

// 获取当前租户的用户列表
this.$axios.get('/api/user/list', {
  params: {
    tenantId: this.tenantId
  }
}).then(response => {
  this.userList = response.data;
});

5. 全局状态管理

5.1 存储租户信息

使用 Vuex 或其他状态管理工具,存储当前租户的信息,方便在整个应用中使用。

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    tenantId: null,
    tenantName: ''
  },
  mutations: {
    setTenantInfo(state, tenant) {
      state.tenantId = tenant.tenantId;
      state.tenantName = tenant.tenantName;
      // 存储到本地存储
      localStorage.setItem('tenantId', tenant.tenantId);
    }
  },
  actions: {
    login({ commit }, tenant) {
      commit('setTenantInfo', tenant);
    }
  }
});

后端部分

1. 多租户实现思路

多租户(Multi - Tenancy)是一种软件架构技术,它允许多个租户(客户)共享同一套软件系统,同时又能保证各个租户的数据相互隔离。在若依框架中实现多租户,可以从以下几个方面入手:
数据库层面:采用租户标识区分不同租户的数据。
请求层面:在请求中携带租户标识,以便在处理请求时区分不同租户。
权限层面:不同租户的用户具有不同的权限。

2. 数据库设计修改

2.1 新增租户表

在数据库中新增一个租户表,用于存储租户的基本信息。

CREATE TABLE `sys_tenant` (
  `tenant_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '租户 ID',
  `tenant_name` varchar(100) NOT NULL COMMENT '租户名称',
  `tenant_code` varchar(50) NOT NULL COMMENT '租户编码',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户表';

2.2 修改用户表

在用户表中新增一个租户 ID 字段,用于关联租户。

ALTER TABLE `sys_user` ADD COLUMN `tenant_id` bigint(20) DEFAULT NULL COMMENT '租户 ID';

3. 请求层面处理

3.1 拦截请求获取租户标识

可以通过自定义拦截器或过滤器来获取请求中的租户标识,并将其存储在上下文中。

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class TenantFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String tenantId = httpRequest.getHeader("X-Tenant-ID");
        if (tenantId != null) {
            // 将租户 ID 存储在上下文中
            TenantContextHolder.setTenantId(Long.parseLong(tenantId));
        }
        try {
            chain.doFilter(request, response);
        } finally {
            // 清除上下文
            TenantContextHolder.clearTenantId();
        }
    }
}

3.2 租户上下文工具类

创建一个租户上下文工具类,用于存储和获取当前请求的租户 ID。

public class TenantContextHolder {
    private static final ThreadLocal<Long> tenantIdThreadLocal = new ThreadLocal<>();

    public static void setTenantId(Long tenantId) {
        tenantIdThreadLocal.set(tenantId);
    }

    public static Long getTenantId() {
        return tenantIdThreadLocal.get();
    }

    public static void clearTenantId() {
        tenantIdThreadLocal.remove();
    }
}

4. 权限层面处理

4.1 修改 Spring Security 配置

在 Spring Security 配置中,添加租户验证逻辑。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
           .authorizeRequests()
               .anyRequest().authenticated()
               .and()
           .formLogin()
               .and()
           .httpBasic()
               .and()
           .addFilterBefore(new TenantFilter(), UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

4.2 修改权限验证逻辑

在权限验证时,需要考虑租户的影响。例如,在查询用户权限时,需要根据租户 ID 进行过滤。

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Long tenantId = TenantContextHolder.getTenantId();
        // 根据租户 ID 和用户名查询用户信息和权限
        // ...
        return null;
    }
}

5. 数据访问层面处理

在数据访问层,需要在查询语句中添加租户 ID 条件,以确保不同租户的数据相互隔离。

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * FROM sys_user WHERE username = #{username} AND tenant_id = #{tenantId}")
    List<User> findUsersByUsernameAndTenantId(String username, Long tenantId);
}

6. 配置拦截器或过滤器

在 Spring Boot 配置类中注册租户过滤器。

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<TenantFilter> tenantFilterRegistration() {
        FilterRegistrationBean<TenantFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new TenantFilter());
        registration.addUrlPatterns("/*");
        registration.setName("tenantFilter");
        registration.setOrder(1);
        return registration;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java后端开发day24--阶段项目(一)

&#xff08;以下内容全部来自上述课程&#xff09; GUI&#xff1a;Graphical User Interface 图形用户接口&#xff0c;采取图形化的方式显示操作界面 分为两套体系&#xff1a;AWT包&#xff08;有兼容问题&#xff09;和Swing包&#xff08;常用&#xff09; 拼图小游戏…

Spring Boot操作MaxComputer(保姆级教程)

目录 引言 一、引入依赖 二、配置文件 application.properties&#xff08;信息用自己的奥&#xff09; 三、实体类User.java 四、UserController 五、UserService 六、UserDao 七、UserDao.xml 八、postman 访问&#xff0c;成功查询数据 附件(修改和删除数据) 引言…

关于Postman自动获取token

在使用postman测试联调接口时&#xff0c;可能每个接口都需要使用此接口生成的令牌做Authorization的Bearer Token验证&#xff0c;最直接的办法可能会是一步一步的点击&#xff0c;如下图&#xff1a; 在Authorization中去选择Bearer Token&#xff0c;然后将获取到的token粘贴…

Ubuntu 22.04 安装Nvidia驱动加速deepseek

一键安装22.04 nvidia 驱动 nvidia 官网下载驱动我的环境是NVIDIA RTX A5000nvidia 文档参考没有安装驱动之前确认自己的型号 lspci | grep -i vga &#xff08;如数字2231&#xff09; 参考docker 支持nvidia &#xff0c;注释了需要的取消注释即可 42行-92行一定要重启服务器…

基于Springboot高校社团管理系统【附源码+文档】

???作者&#xff1a; 米罗学长 ???个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 ???各类成品Java毕设 。javaweb&#xff0c;ssm&#xff0c;springboot等项目&#xff0c;欢迎咨询。 ???程序开发、技术解答、代码讲解、文档&am…

PHP:IDEA开发工具配置XDebug,断点调试

文章目录 一、php.ini配置二、IDEA配置 一、php.ini配置 [xdebug] zend_extension"F:\wamp64\bin\php\php7.4.0\ext\php_xdebug-2.8.0-7.4-vc15-x86_64.dll" xdebug.remote_enable on xdebug.remote_host 127.0.0.1 xdebug.remote_port 9001 xdebug.idekey"…

金融项目实战

测试流程 测试流程 功能测试流程 功能测试流程 需求评审制定测试计划编写测试用例和评审用例执行缺陷管理测试报告 接口测试流程 接口测试流程 需求评审制定测试计划分析api文档编写测试用例搭建测试环境编写脚本执行脚本缺陷管理测试报告 测试步骤 测试步骤 需求评审 需求评…

期权学习与期权异动

期权异动网站 https://www.barchart.com/options/unusual-activity/stocks Delta 衡量期权价格对标的资产价格变动的敏感度的指标。它表示标的资产价格每变动一个单位&#xff0c;期权价格预期会变动多少。 取值范围&#xff1a; 看涨期权&#xff08;Call Option&#xff…

一次有趣的前后端跨越排查

进行前后端代码联调的时候&#xff0c;使用axios调用后端请求&#xff0c;因为都是本地进行联调&#xff0c;所以没有考虑跨域的问题&#xff0c;写了一个get的请求接口&#xff0c;请求后端时&#xff0c;突然跳出下面的问题&#xff1a; 错误的信息一看很像就是跨域的问题&…

创建一个简单的spring boot+vue前后端分离项目

一、环境准备 此次实验需要的环境&#xff1a; jdk、maven、nvm和node.js 开发工具&#xff1a;idea或者Spring Tool Suite 4&#xff0c;前端可使用HBuilder X&#xff0c;数据库Mysql 下面提供maven安装与配置步骤和nvm安装与配置步骤&#xff1a; 1、maven安装与配置 1…

【0011】HTML其他文本格式化标签详解(em标签、strong标签、b标签、i标签、sup标签、sub标签......)

如果你觉得我的文章写的不错&#xff0c;请关注我哟&#xff0c;请点赞、评论&#xff0c;收藏此文章&#xff0c;谢谢&#xff01; 本文内容体系结构如下&#xff1a; 本文旨在深入探讨HTML中其他的文本格式化标签&#xff0c;主要有<em> 标签、<strong> 标签、…

从零开始:H20服务器上DeepSeek R1 671B大模型部署与压力测试全攻略

前言 最近&#xff0c;我有幸在工作中接触到了DeepSeek R1 671B模型&#xff0c;这是目前中文开源领域参数量最大的高质量模型之一。DeepSeek团队在2024年推出的这款模型&#xff0c;以其惊人的6710亿参数量和出色的推理性能&#xff0c;引起了业界广泛关注。 作为一名AI基础…

mySQL复习

目录 一.写在前面 二.介绍 三.选择语句 四.内连接 五.列属性 一.写在前面 课程视频&#xff1a;【中字】SQL进阶教程 | 史上最易懂SQL教程&#xff01;10小时零基础成长SQL大师&#xff01;&#xff01;_哔哩哔哩_bilibili 课程所需资料&#xff1a; 链接&#xff1a;h…

基于SpringBoot+Vue的医院挂号管理系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

golang介绍,特点,项目结构,基本变量类型与声明介绍(数组,切片,映射),控制流语句介绍(条件,循环,switch case)

目录 golang 介绍 面向并发 面向组合 特点 项目结构 图示 入口文件 main.go 基本变量类型与声明 介绍 声明变量 常量 字符串(string) 字符串格式化 空接口类型 数组 切片 创建对象 追加元素 复制切片 map(映射) 创建对象 使用 多重赋值 控制流语句…

3.2-A-L1-2-第15讲-冒泡排序 mochen @denglexi

博观而约取 厚积而薄发 Observe extensively but select wisely; accumulate deeply but release sparingly. 每次比较两个相邻的元素&#xff0c;如果它们的顺序错误就把它 们交换过来。 每一轮进行两两比较&#xff0c;将该轮中最大/最小的值冒出来。 冒泡程序核心代码&#…

25、泛型

十二章、泛型 12-1 为何要有泛型 1、泛型&#xff1a;是一种标签。把元素的类型设计成一个参数&#xff0c;这个类型参数就叫做泛型 2、所谓泛型&#xff0c;就是允许在定义类、接口时通过一个标识表示类中 某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在…

[KEIL]单片机技巧 01

1、查看外设寄存器的值 配合对应的芯片开发手册以查看寄存器及其每一位的意义&#xff0c;可以解决90%以上的单纯的片内外设bug&#xff0c;学会如何通过寄存器的值来排外设上的蛊是嵌入式开发从小白到入门的重要一步&#xff0c;一定要善于使用这个工具&#xff0c;而不是外设…

TCP/IP 5层协议簇:网络层(IP数据包的格式、路由器原理)

目录 1. TCP/IP 5层协议簇 2. IP 三层包头协议 3. 路由器原理 4. 交换机和路由的对比 1. TCP/IP 5层协议簇 如下&#xff1a; 2. IP 三层包头协议 数据包如下&#xff1a;IP包头不是固定的&#xff0c;每一个数字是一个bit 其中数据部分是上层的内容&#xff0c;IP包头最…

免费轻巧多功能 PDF 处理工具:转换、压缩、提取一应俱全

软件技术 今天要给大家分享一款超实用的 PDF 处理工具&#xff0c;它免费又轻巧&#xff0c;如同随时待命的得力小帮手&#xff0c;功能之强大超乎想象&#xff0c;真的值得大家收藏。 这款工具是绿色版软件&#xff0c;解压后开启&#xff0c;满满的 PDF 处理功能便映入眼帘…