数据权限拦截器,多租户拦截器

这篇具有很好参考价值的文章主要介绍了数据权限拦截器,多租户拦截器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、背景介绍

WEB类型软件产品,在Java(SpringBoot)+MybatisPlus架构场景下,本文针对下面两个问题,提供解决方案:

  • 多租户的产品,想在表内级别上,实现租户数据隔离(分表、分库方案不在本文讨论范围内)。
  • ToB、ToG类型的软件产品,需要实现数据权限鉴权。例如用户数据、部门数据、租户数据等不同级别的鉴权。

Demo源码仓库: java-test: java练习Demo项目 - Gitee.com

二、MybatisPlus插件

MyBatis-Plus官网

MyBatis-Plus插件

目前MybatisPlus官方文档中已有的插件功能:

  • 自动分页: PaginationInnerInterceptor
  • 多租户: TenantLineInnerInterceptor
  • 动态表名: DynamicTableNameInnerInterceptor
  • 乐观锁: OptimisticLockerInnerInterceptor
  • sql 性能规范: IllegalSQLInnerInterceptor
  • 防止全表更新与删除: BlockAttackInnerInterceptor

各种插件的使用方法,网上资料也比较多,大家可自行百度。

另外,在MybatisPlus 3.x及以后的版本里,我们可以从源码里找到DataPermissionInterceptor数据权限处理器插件,虽然截止本文编写时(20230117),官网文档中还没有此插件的说明,但已经能百度到DataPermissionInterceptor拦截器的一些使用案例了。

个人感觉相比多租户拦截器TenantLineInnerInterceptor的用法,官方提供的数据权限拦截器DataPermissionInterceptor使用起来还是过于复杂,而且针对CRUD操作的鉴权功能也不够强大,因此参考多租户拦截器的实现原理,对数据权限拦截器进行了改造,后续有空了会将改造后的代码推荐给官方,看是否可以被采纳。见Demo源码仓库。

MybatisPlus的maven依赖:

<dependencies>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <!-- 截止本文编写时,最新的MP版本 -->
        <version>3.5.3.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.3.4.RELEASE</version>
    </dependency>
</dependencies>

本文后续的例子中,所用的数据库结构:

/*
 Navicat Premium Data Transfer

 Source Server         : mysql8
 Source Server Type    : MySQL
 Source Server Version : 80027
 Source Host           : localhost:3306
 Source Schema         : wsp-test

 Target Server Type    : MySQL
 Target Server Version : 80027
 File Encoding         : 65001

 Date: 17/01/2023 16:26:17
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for wsp_org
-- ----------------------------
DROP TABLE IF EXISTS `wsp_org`;
CREATE TABLE `wsp_org`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `create_time` timestamp NOT NULL COMMENT '创建时间',
  `update_time` timestamp NOT NULL COMMENT '更新时间',
  `org_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '部门名称',
  `org_address` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '部门地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for wsp_role
-- ----------------------------
DROP TABLE IF EXISTS `wsp_role`;
CREATE TABLE `wsp_role`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `create_time` timestamp NOT NULL COMMENT '创建时间',
  `update_time` timestamp NOT NULL COMMENT '更新时间',
  `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id',
  `role_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  `role_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色编码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for wsp_user
-- ----------------------------
DROP TABLE IF EXISTS `wsp_user`;
CREATE TABLE `wsp_user`  (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `create_time` timestamp NOT NULL COMMENT '创建时间',
  `create_by` bigint unsigned NOT NULL COMMENT '创建人',
  `update_time` timestamp NOT NULL COMMENT '更新时间',
  `tenant_id` bigint NOT NULL COMMENT '租户id',
  `org_id` bigint NOT NULL COMMENT '部门id',
  `role_id` bigint NOT NULL COMMENT '角色id',
  `name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '姓名',
  `age` int unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

三、基于MybatisPlus的多租户插件

1、开发步骤

TenantLineInnerInterceptor是MybatisPlus中提供的多租户插件,其使用方法大致分为下面三步:

步骤一、设置环境变量,配置拦截规则

对夸租户的表设置白名单,忽略多租户拦截,这些配置可以放到配置文件中进行环境配置,例如:

tenant:
  enable: true
  column: tenant_id
  filterTables:
  ignoreTables:
    - wsp_org
  ignoreLoginNames:

例如wsp_org表结构中,没有tenant_id多租户字段,那么多租户拦截器不拦截该表。

import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;

/**
 * 多租户配置类
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "tenant")
public class TenantProperties {
    /**
     * 是否开启多租户
     */
    private Boolean enable = true;

    /**
     * 租户id字段名
     */
    private String column = "tenant_id";

    /**
     * 需要进行租户id过滤的表名集合
     */
    private List<String> filterTables;

    /**
     * 需要忽略的多租户的表,此配置优先filterTables,若此配置为空则启用filterTables
     */
    private List<String> ignoreTables;

    /**
     * 需要排除租户过滤的登录用户名
     */
    private List<String> ignoreLoginNames;
}

步骤二、实现TenantLineHandler接口

实现TenantLineHandler接口

import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.sky.wsp.mybatis.plus.utils.SecurityContextHolder;
import com.sky.wsp.mybatis.plus.config.properties.TenantProperties;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;

import java.util.List;

/**
 * 多租户处理类
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
public class MultiTenantHandler implements TenantLineHandler {

    private final TenantProperties properties;

    public MultiTenantHandler(TenantProperties properties) {
        this.properties = properties;
    }

    /**
     * 获取租户 ID 值表达式,只支持单个 ID 值
     * <p>
     *
     * @return 租户 ID 值表达式
     */
    @Override
    public Expression getTenantId() {
        Long tenantId = SecurityContextHolder.getTenantId();
        return new LongValue(tenantId);
    }

    /**
     * 获取租户字段名
     * <p>
     * 默认字段名叫: tenant_id
     *
     * @return 租户字段名
     */
    @Override
    public String getTenantIdColumn() {
        return properties.getColumn();
    }

    /**
     * 根据表名判断是否忽略拼接多租户条件
     * <p>
     * 默认都要进行解析并拼接多租户条件
     *
     * @param tableName 表名
     * @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件
     */
    @Override
    public boolean ignoreTable(String tableName) {

        //忽略指定用户对租户的数据过滤
        List<String> ignoreLoginNames=properties.getIgnoreLoginNames();
        String loginName=SecurityContextHolder.getUsername();
        if(null!=ignoreLoginNames && ignoreLoginNames.contains(loginName)){
            return true;
        }

        //忽略指定表对租户数据的过滤
        List<String> ignoreTables = properties.getIgnoreTables();
        if (null != ignoreTables && ignoreTables.contains(tableName)) {
            return true;
        }

        return false;
    }
}

步骤三、启用TenantLineInnerInterceptor多租户拦截器

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.sky.wsp.mybatis.plus.config.properties.TenantProperties;
import com.sky.wsp.mybatis.plus.handler.DBMetaObjectHandler;
import com.sky.wsp.mybatis.plus.handler.MultiTenantHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MybatisPlus配置类
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({
        TenantProperties.class,
        DataPermissionProperties.class
})
public class MybatisPlusConfig {

    /**
     * 单页分页条数限制(默认无限制,参见 插件#handlerLimit 方法)
     */
    private static final Long MAX_LIMIT = 1000L;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(TenantProperties tenantProperties) {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        if (Boolean.TRUE.equals(tenantProperties.getEnable())) {
            // 启用多租户拦截
            interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MultiTenantHandler(tenantProperties)));
        }
        return interceptor;
    }

    @Bean
    @ConditionalOnMissingBean
    public MetaObjectHandler metaObjectHandler() {
        return new DBMetaObjectHandler();
    }

}

2、执行结果

针对MybatisPlus提供的API、自定义Mapper中的statement(不清楚statement概念的同学可自行百度)我都进行了测试,均可正常拦截,下面附上一些拦截前后SQL对比的例子:

例1:使用MybatisPlus的insert方法,添加数据时会自动初始化tenant_id列

处理前 处理后
INSERT INTO wsp_user (
create_time,
create_by,
update_time,
org_id,
role_id,
NAME,
age
)
VALUES
(
?,
?,
?,
?,
?,
?,
?
)
INSERT INTO wsp_user (
create_time,
create_by,
update_time,
org_id,
role_id,
NAME,
age,
tenant_id
)
VALUES
(?,
?,
?,
?,
?,
?,
?,
1)

例2:使用MybatisPlus的selectById方法,添加数据时会自动初始化tenant_id列

处理前 处理后
SELECT
id,
create_time,
update_time,
tenant_id,
org_id,
role_id,
NAME,
age
FROM
wsp_user
WHERE
id =?
SELECT
id,
create_time,
update_time,
tenant_id,
org_id,
role_id,
NAME,
age
FROM
wsp_user
WHERE
id = ?
AND tenant_id = 1

例3:使用自定义Mapper的statement方法

处理前 处理后
SELECT
id,
create_time,
update_time,
tenant_id,
org_id,
NAME,
age
FROM
wsp_user AS USER
WHERE
USER.id = ?
SELECT
id,
create_time,
update_time,
tenant_id,
org_id,
NAME,
age
FROM
wsp_user AS USER
WHERE
USER.id = ?
AND USER.tenant_id = 1

例4:使用自定义Mapper的statement方法,进行多表关联查询

处理前 处理后
SELECT USER
.tenant_id,
USER.org_id,
org.org_name,
org.org_address,
USER.role_id,
role.role_name,
role.role_code,
USER.id AS user_id,
USER.NAME AS user_name,
USER.age AS user_age
FROM
wsp_user
AS USER LEFT JOIN wsp_org AS org ON USER.org_id = org.id
LEFT JOIN wsp_role AS role ON USER.role_id = role.id
WHERE
USER.id = ?
SELECT USER
.tenant_id,
USER.org_id,
org.org_name,
org.org_address,
USER.role_id,
role.role_name,
role.role_code,
USER.id AS user_id,
USER.NAME AS user_name,
USER.age AS user_age
FROM
wsp_user
AS USER LEFT JOIN wsp_org AS org ON USER.org_id = org.id
LEFT JOIN wsp_role AS role ON USER.role_id = role.id
AND role.tenant_id = 1
WHERE
USER.id = ?
AND USER.tenant_id = 1

四、基于MybatisPlus实现自定义数据权限插件

由于官方提供的数据权限拦截器DataPermissionInterceptor,只能自己拼装SQL来实现数据鉴权,拼装SQL操作比较困难,因此参考多租户拦截器,对数据权限拦截器进行了改造,简化了使用难度,见Demo源码仓库:

  • 支持自定义数据权限标记列,即使用表的哪个列进行数据权限过滤
  • 支持自定义表白名单、账号白名单
  • 数据权限包括:是否是创建者、是否有部门数据权限
  • select查询时,自动补充数据权限过滤条件
  • insert添加时,自动校验插入数据的部门外键,是否在当前登录人的操作权限范围内
  • update更新时,自动校验更新数据的部门外键,是否在当前登录人的操作权限范围内
  • delete删除时,自动补充数据权限过滤条件

注意:数据权限的id外键,在新建数据时,是无法通过拦截器进行初始化的,因为一个账号的数据权限,通常会包含多个部门,那新建数据时,到底是属于哪个部门下的数据,不好判断,因此由用户自己(开发人员)在业务代码中对数据权限id进行初始化。

1、开发步骤

类似多租户插件,数据权限插件使用方法也大致分为下面三步:

步骤一、设置环境变量,配置拦截规则

对夸部门共享的表设置白名单,忽略多数据权限拦截,这些配置可以放到配置文件中进行环境配置,例如:

data:
  permission:
    enable: true
    # 创建人的标记列
    dataCreatorColumn: create_by
    # 部门数据权限的标记列
    dataPermissionIdColumn: org_id
    filterTables:
    ignoreTables:
      # 不进行数据鉴权拦截的表
      - wsp_org
      - wsp_role
    ignoreLoginNames:

例如wsp_org、wsp_role表结构中,没有org_id部门外键,那么数据权限拦截器不拦截该表。

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;


/**
 * 数据权限配置类
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "data.permission")
public class DataPermissionProperties {
    /**
     * 是否开启数据权限拦截
     */
    private Boolean enable = true;

    /**
     * 数据创建人字段名
     */
    private String dataCreatorColumn = "creator";

    /**
     * 数据权限id字段名
     */
    private String dataPermissionIdColumn = "permission_id";

    /**
     * 需要进行数据权限id过滤的表名集合
     */
    private List<String> filterTables;

    /**
     * 需要忽略的多数据权限的表,此配置优先filterTables,若此配置为空则启用filterTables
     */
    private List<String> ignoreTables;

    /**
     * 需要排除数据权限过滤的登录用户名
     */
    private List<String> ignoreLoginNames;
}

步骤二、实现MyDataPermissionHandler接口

实现MyDataPermissionHandler接口,(这个接口也是参考多租户的接口新建的)

import com.sky.wsp.mybatis.plus.config.properties.DataPermissionProperties;
import com.sky.wsp.mybatis.plus.plugins.handler.MyDataPermissionHandler;
import com.sky.wsp.mybatis.plus.utils.SecurityContextHolder;

import java.util.List;

/**
 * 基于用户组织机构(Org)的数据权限处理类
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
public class OrgDataPermissionHandler implements MyDataPermissionHandler {

    private final DataPermissionProperties properties;

    public OrgDataPermissionHandler(DataPermissionProperties properties) {
        this.properties = properties;
    }

    @Override
    public Long getDataCreator() {
        // user_id作为creator
        return SecurityContextHolder.getUserId();
    }

    @Override
    public String getDataCreatorColumn() {
        // user_id作为creator
        return properties.getDataCreatorColumn();
    }

    @Override
    public List<Long> getDataPermissionIdSet() {
        // org_id作为数据权限
        return SecurityContextHolder.getOrgIds();
    }

    @Override
    public String getDataPermissionIdColumn() {
        // org_id作为数据权限
        return properties.getDataPermissionIdColumn();
    }

    @Override
    public boolean ignoreTable(String tableName) {

        //忽略指定用户对数据权限的过滤
        List<String> ignoreLoginNames=properties.getIgnoreLoginNames();
        String loginName=SecurityContextHolder.getUsername();
        if(null!=ignoreLoginNames && ignoreLoginNames.contains(loginName)){
            return true;
        }

        //忽略指定表对数据权限的过滤
        List<String> ignoreTables = properties.getIgnoreTables();
        if (null != ignoreTables && ignoreTables.contains(tableName)) {
            return true;
        }
        return false;
    }
}

步骤三、启用MyDataPermissionInterceptor多租户拦截器

MyDataPermissionInterceptor就是参考多租户拦截器实现的数据权限拦截器,核心逻辑都在这个类里。

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.sky.wsp.mybatis.plus.config.properties.DataPermissionProperties;
import com.sky.wsp.mybatis.plus.config.properties.TenantProperties;
import com.sky.wsp.mybatis.plus.handler.DBMetaObjectHandler;
import com.sky.wsp.mybatis.plus.handler.MultiTenantHandler;
import com.sky.wsp.mybatis.plus.handler.OrgDataPermissionHandler;
import com.sky.wsp.mybatis.plus.plugins.inner.MyDataPermissionInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MybatisPlus配置类
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({
        TenantProperties.class,
        DataPermissionProperties.class
})
public class MybatisPlusConfig {

    /**
     * 单页分页条数限制(默认无限制,参见 插件#handlerLimit 方法)
     */
    private static final Long MAX_LIMIT = 1000L;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(TenantProperties tenantProperties, DataPermissionProperties dataPermissionProperties) {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        if (Boolean.TRUE.equals(tenantProperties.getEnable())) {
            // 启用多租户拦截
            interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MultiTenantHandler(tenantProperties)));
        }
        if (Boolean.TRUE.equals(dataPermissionProperties.getEnable())) {
            // 启用数据权限拦截
            interceptor.addInnerInterceptor(new MyDataPermissionInterceptor(new OrgDataPermissionHandler(dataPermissionProperties)));
        }
        // 分页拦截
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInterceptor.setMaxLimit(MAX_LIMIT);
        interceptor.addInnerInterceptor(paginationInterceptor);
        // 乐观锁拦截
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

    @Bean
    @ConditionalOnMissingBean
    public MetaObjectHandler metaObjectHandler() {
        return new DBMetaObjectHandler();
    }

}

2、执行结果

针对MybatisPlus提供的API、自定义Mapper中的statement(不清楚statement概念的同学可自行百度)我都进行了测试,均可正常拦截,下面附上一些拦截前后SQL对比的例子:

处理前 处理后
SELECT USER
.tenant_id,
USER.org_id,
org.org_name,
org.org_address,
USER.role_id,
role.role_name,
role.role_code,
USER.id AS user_id,
USER.NAME AS user_name,
USER.age AS user_age
FROM
wsp_user
AS USER LEFT JOIN wsp_org AS org ON USER.org_id = org.id
LEFT JOIN wsp_role AS role ON USER.role_id = role.id
WHERE
USER.id = ?
SELECT USER
.tenant_id,
USER.org_id,
org.org_name,
org.org_address,
USER.role_id,
role.role_name,
role.role_code,
USER.id AS user_id,
USER.NAME AS user_name,
USER.age AS user_age
FROM
wsp_user
AS USER LEFT JOIN wsp_org AS org ON USER.org_id = org.id
LEFT JOIN wsp_role AS role ON USER.role_id = role.id
AND role.tenant_id = 1
WHERE
USER.id = ?
AND USER.tenant_id = 1
AND (
create_by = 1
OR USER.org_id IN ( 4, 5, 6 ))

其他的增删改查的例子,同多租户拦截器,这里就不赘述了。

五、忽略拦截

在一些场景下,无需多租户拦截、无需数据鉴权拦截,或者对于一些超级管理员使用的接口,希望夸租户查询、免数据鉴权时,可以通过下面几种方式实现忽略拦截:文章来源地址https://www.toymoban.com/news/detail-786297.html

  • 使用MybatisPlus框架自带的@InterceptorIgnore注解,以用在Mapper类上,也可以用在方法上
  • 添加超级用户账号白名单,在自定义的Handler里进行逻辑判断,跳过拦截
  • 添加数据表白名单,在自定义的Handler里进行逻辑判断,跳过拦截
 /**
     * 使用@InterceptorIgnore注解,忽略多租户拦截 <br/>
     * 注解@InterceptorIgnore可以用在Mapper类上,也可以用在方法上
     *
     * @param id
     * @return
     */
    @InterceptorIgnore(tenantLine = "true")
    UserOrgVO myFindByIdNoTenant(@Param(value = "id") Long id);
tenant:
  enable: true
  column: tenant_id
  filterTables:
  ignoreTables:
    # 不进行多租户拦截的表
    - wsp_org
  ignoreLoginNames:
    # 这里配置了ID,需要使用username的,可在MultiTenantHandler中自己实现判断逻辑
    - 99
    - 98

data:
  permission:
    enable: true
    dataCreatorColumn: create_by
    dataPermissionIdColumn: org_id
    filterTables:
    ignoreTables:
      # 不进行数据鉴权拦截的表
      - wsp_org
      - wsp_role
    ignoreLoginNames:
      # 这里配置了ID,需要使用username的,可在OrgDataPermissionHandler中自己实现判断逻辑
      - 99 
      - 98

六、参考

  • Saas.数据权限控制(Sql解析)
  • or 和 in 的效率对比
  • 常见的功能权限模型

到了这里,关于数据权限拦截器,多租户拦截器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 7.5 SpringBoot 拦截器Interceptor实战 统一角色权限校验

    在【 7.1 】管理员图书录入和修改API,当时预告过:并没有写【校验是否是管理员】的逻辑,因为是通用逻辑,会单写一篇来细讲,那么今天就来安排! 角色权限校验 ,是保证接口安全必备的能力:有权限才可以操作!所以,一般对于这种通用逻辑,推荐不与主业务逻辑耦合

    2024年02月16日
    浏览(29)
  • 掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!

    (1)浏览器发送一个请求会先到Tomcat的web服务器。 (2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源。 (3)如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问。 (4)如果是动态资源,就需要交给项目的后台代码进行处理。 (5)在找到具体的方法之前

    2024年01月22日
    浏览(36)
  • MyBatis拦截器优雅实现数据脱敏

    现代网络环境中,敏感数据的处理是至关重要的。敏感数据包括个人身份信息、银行账号、手机号码等,泄露这些数据可能导致用户隐私泄露、财产损失等严重后果。因此,对敏感数据进行脱敏处理是一种必要的安全措施。 比如页面上常见的敏感数据都是加*遮挡处理过的,

    2024年02月06日
    浏览(33)
  • 基于Mybatis-Plus拦截器实现MySQL数据加解密

    用户的一些敏感数据,例如手机号、邮箱、身份证等信息,在数据库以明文存储时会存在数据泄露的风险,因此需要进行加密, 但存储数据再被取出时,需要进行解密,因此加密算法需要使用对称加密算法。 常用的对称加密算法有AES、DES、RC、BASE64等等,各算法的区别与优劣

    2024年02月16日
    浏览(32)
  • 基于MybatisPlus拦截器实现数据库关键字处理及官方做法

    有些老的数据库当中可能会有些字段和数据库冲突,使用mybatisPlus执行Sql的时候有时候会执行失败,前段时间和群友讨论的时候他说遇到了这个问题,当时我提议让他用我以前写的一个自定义注解+mybatis拦截器实现权限控制里边的工具类改造一下。 他说不能实现,然后

    2024年04月25日
    浏览(32)
  • 关于MyBatis拦截器失效问题的解决(多数据源、分页插件)

    最近做了一个备份被delete语句删除的数据的小插件,是用MyBatis的拦截器去做的。 但是发现在一个项目中会失效,没有去备份删除的数据,查看日志发现请求并没有进入到拦截器中,换句话说就是拦截器失效了。 百度了一下(哎,百度)发现说的最多的就是分页插件导致的,

    2024年02月14日
    浏览(29)
  • .Net Core Entity Framework Core 的基础封装 -数据库操作拦截器

    自己制作的一个基于Entity Framework Core 的数据库操作拦截器,可以打印数据库执行sql,方便开发调试,代码如下: 运行结果如下:  

    2024年02月22日
    浏览(41)
  • VUE3 请求拦截器 响应拦截器

    1,导入axios  (使用axios进行接口的请求,页面发送http请求,很多情况我们要对请求和其响应进行特定的处理,如:判断token,设置请求头。如果请求数非常多,单独对每一个请求进行处理会变得非常麻烦,程序的优雅性也会大打折扣。所以axios为开发者提供了这样一个API:拦

    2024年02月16日
    浏览(39)
  • SpringBoot加入拦截器——登录拦截器的实现

            拦截器 Interceptor 在 Spring MVC 中的地位等同于 Servlet 规范中的过滤器 Filter,拦截的是处理器的执行,由于是全局行为,因此常用于做一些通用的功能,如请求日志打印、权限控制等。         核心原理:AOP思想 preHandle:  预先处理,在目标的controller方法执行之前,进行

    2024年02月15日
    浏览(32)
  • 自定义注解与拦截器实现不规范sql拦截(拦截器实现篇)

    最近考虑myBatis中sql语句使用规范的问题,如果漏下条件或者写一些不规范语句会对程序性能造成很大影响。最好的方法就是利用代码进行限制,通过拦截器进行sql格式的判断在自测环节就能找到问题。写了个简单情景下的demo,并通过idea插件来将myBatis的mapper方法都打上拦截器

    2024年01月22日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包