天天看點

資料權限攔截器,多租戶攔截器一、背景介紹二、MybatisPlus插件三、基于MybatisPlus的多租戶插件四、基于MybatisPlus實作自定義資料權限插件五、忽略攔截六、參考

一、背景介紹

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 [email protected]
 * @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 [email protected]
 * @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 [email protected]
 * @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 [email protected]
 * @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 [email protected]
 * @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 [email protected]
 * @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 ))

其他的增删改查的例子,同多租戶攔截器,這裡就不贅述了。

五、忽略攔截

在一些場景下,無需多租戶攔截、無需資料鑒權攔截,或者對于一些超級管理者使用的接口,希望誇租戶查詢、免資料鑒權時,可以通過下面幾種方式實作忽略攔截:

  • 使用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 的效率對比
  • 常見的功能權限模型