当前位置:   article > 正文

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

tenantlinehandler

一、背景介绍

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依赖:

  1. <dependencies>
  2. <dependency>
  3. <groupId>com.baomidou</groupId>
  4. <artifactId>mybatis-plus-boot-starter</artifactId>
  5. <!-- 截止本文编写时,最新的MP版本 -->
  6. <version>3.5.3.1</version>
  7. </dependency>
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>8.0.29</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-web</artifactId>
  16. <version>2.3.4.RELEASE</version>
  17. </dependency>
  18. </dependencies>

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

  1. /*
  2. Navicat Premium Data Transfer
  3. Source Server : mysql8
  4. Source Server Type : MySQL
  5. Source Server Version : 80027
  6. Source Host : localhost:3306
  7. Source Schema : wsp-test
  8. Target Server Type : MySQL
  9. Target Server Version : 80027
  10. File Encoding : 65001
  11. Date: 17/01/2023 16:26:17
  12. */
  13. SET NAMES utf8mb4;
  14. SET FOREIGN_KEY_CHECKS = 0;
  15. -- ----------------------------
  16. -- Table structure for wsp_org
  17. -- ----------------------------
  18. DROP TABLE IF EXISTS `wsp_org`;
  19. CREATE TABLE `wsp_org` (
  20. `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  21. `create_time` timestamp NOT NULL COMMENT '创建时间',
  22. `update_time` timestamp NOT NULL COMMENT '更新时间',
  23. `org_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '部门名称',
  24. `org_address` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '部门地址',
  25. PRIMARY KEY (`id`) USING BTREE
  26. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic;
  27. -- ----------------------------
  28. -- Table structure for wsp_role
  29. -- ----------------------------
  30. DROP TABLE IF EXISTS `wsp_role`;
  31. CREATE TABLE `wsp_role` (
  32. `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  33. `create_time` timestamp NOT NULL COMMENT '创建时间',
  34. `update_time` timestamp NOT NULL COMMENT '更新时间',
  35. `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id',
  36. `role_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  37. `role_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色编码',
  38. PRIMARY KEY (`id`) USING BTREE
  39. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;
  40. -- ----------------------------
  41. -- Table structure for wsp_user
  42. -- ----------------------------
  43. DROP TABLE IF EXISTS `wsp_user`;
  44. CREATE TABLE `wsp_user` (
  45. `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  46. `create_time` timestamp NOT NULL COMMENT '创建时间',
  47. `create_by` bigint unsigned NOT NULL COMMENT '创建人',
  48. `update_time` timestamp NOT NULL COMMENT '更新时间',
  49. `tenant_id` bigint NOT NULL COMMENT '租户id',
  50. `org_id` bigint NOT NULL COMMENT '部门id',
  51. `role_id` bigint NOT NULL COMMENT '角色id',
  52. `name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '姓名',
  53. `age` int unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  54. PRIMARY KEY (`id`) USING BTREE
  55. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
  56. SET FOREIGN_KEY_CHECKS = 1;

三、基于MybatisPlus的多租户插件

1、开发步骤

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

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

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

  1. tenant:
  2. enable: true
  3. column: tenant_id
  4. filterTables:
  5. ignoreTables:
  6. - wsp_org
  7. ignoreLoginNames:

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

  1. import org.springframework.boot.context.properties.ConfigurationProperties;
  2. import java.util.List;
  3. /**
  4. * 多租户配置类
  5. *
  6. * @author wangshaopeng@talkweb.com.cn
  7. * @Date 2023-01-11
  8. */
  9. @Getter
  10. @Setter
  11. @ConfigurationProperties(prefix = "tenant")
  12. public class TenantProperties {
  13. /**
  14. * 是否开启多租户
  15. */
  16. private Boolean enable = true;
  17. /**
  18. * 租户id字段名
  19. */
  20. private String column = "tenant_id";
  21. /**
  22. * 需要进行租户id过滤的表名集合
  23. */
  24. private List<String> filterTables;
  25. /**
  26. * 需要忽略的多租户的表,此配置优先filterTables,若此配置为空则启用filterTables
  27. */
  28. private List<String> ignoreTables;
  29. /**
  30. * 需要排除租户过滤的登录用户名
  31. */
  32. private List<String> ignoreLoginNames;
  33. }

步骤二、实现TenantLineHandler接口

实现TenantLineHandler接口

  1. import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
  2. import com.sky.wsp.mybatis.plus.utils.SecurityContextHolder;
  3. import com.sky.wsp.mybatis.plus.config.properties.TenantProperties;
  4. import net.sf.jsqlparser.expression.Expression;
  5. import net.sf.jsqlparser.expression.LongValue;
  6. import java.util.List;
  7. /**
  8. * 多租户处理类
  9. *
  10. * @author wangshaopeng@talkweb.com.cn
  11. * @Date 2023-01-11
  12. */
  13. public class MultiTenantHandler implements TenantLineHandler {
  14. private final TenantProperties properties;
  15. public MultiTenantHandler(TenantProperties properties) {
  16. this.properties = properties;
  17. }
  18. /**
  19. * 获取租户 ID 值表达式,只支持单个 ID 值
  20. * <p>
  21. *
  22. * @return 租户 ID 值表达式
  23. */
  24. @Override
  25. public Expression getTenantId() {
  26. Long tenantId = SecurityContextHolder.getTenantId();
  27. return new LongValue(tenantId);
  28. }
  29. /**
  30. * 获取租户字段名
  31. * <p>
  32. * 默认字段名叫: tenant_id
  33. *
  34. * @return 租户字段名
  35. */
  36. @Override
  37. public String getTenantIdColumn() {
  38. return properties.getColumn();
  39. }
  40. /**
  41. * 根据表名判断是否忽略拼接多租户条件
  42. * <p>
  43. * 默认都要进行解析并拼接多租户条件
  44. *
  45. * @param tableName 表名
  46. * @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件
  47. */
  48. @Override
  49. public boolean ignoreTable(String tableName) {
  50. //忽略指定用户对租户的数据过滤
  51. List<String> ignoreLoginNames=properties.getIgnoreLoginNames();
  52. String loginName=SecurityContextHolder.getUsername();
  53. if(null!=ignoreLoginNames && ignoreLoginNames.contains(loginName)){
  54. return true;
  55. }
  56. //忽略指定表对租户数据的过滤
  57. List<String> ignoreTables = properties.getIgnoreTables();
  58. if (null != ignoreTables && ignoreTables.contains(tableName)) {
  59. return true;
  60. }
  61. return false;
  62. }
  63. }

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

  1. import com.baomidou.mybatisplus.annotation.DbType;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
  4. import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
  5. import com.sky.wsp.mybatis.plus.config.properties.TenantProperties;
  6. import com.sky.wsp.mybatis.plus.handler.DBMetaObjectHandler;
  7. import com.sky.wsp.mybatis.plus.handler.MultiTenantHandler;
  8. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  9. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. /**
  13. * MybatisPlus配置类
  14. *
  15. * @author wangshaopeng@talkweb.com.cn
  16. * @Date 2023-01-11
  17. */
  18. @Configuration(proxyBeanMethods = false)
  19. @EnableConfigurationProperties({
  20. TenantProperties.class,
  21. DataPermissionProperties.class
  22. })
  23. public class MybatisPlusConfig {
  24. /**
  25. * 单页分页条数限制(默认无限制,参见 插件#handlerLimit 方法)
  26. */
  27. private static final Long MAX_LIMIT = 1000L;
  28. @Bean
  29. public MybatisPlusInterceptor mybatisPlusInterceptor(TenantProperties tenantProperties) {
  30. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  31. if (Boolean.TRUE.equals(tenantProperties.getEnable())) {
  32. // 启用多租户拦截
  33. interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MultiTenantHandler(tenantProperties)));
  34. }
  35. return interceptor;
  36. }
  37. @Bean
  38. @ConditionalOnMissingBean
  39. public MetaObjectHandler metaObjectHandler() {
  40. return new DBMetaObjectHandler();
  41. }
  42. }

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、开发步骤

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

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

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

  1. data:
  2. permission:
  3. enable: true
  4. # 创建人的标记列
  5. dataCreatorColumn: create_by
  6. # 部门数据权限的标记列
  7. dataPermissionIdColumn: org_id
  8. filterTables:
  9. ignoreTables:
  10. # 不进行数据鉴权拦截的表
  11. - wsp_org
  12. - wsp_role
  13. ignoreLoginNames:

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

  1. import org.springframework.boot.context.properties.ConfigurationProperties;
  2. import java.util.List;
  3. /**
  4. * 数据权限配置类
  5. *
  6. * @author wangshaopeng@talkweb.com.cn
  7. * @Date 2023-01-11
  8. */
  9. @Getter
  10. @Setter
  11. @ConfigurationProperties(prefix = "data.permission")
  12. public class DataPermissionProperties {
  13. /**
  14. * 是否开启数据权限拦截
  15. */
  16. private Boolean enable = true;
  17. /**
  18. * 数据创建人字段名
  19. */
  20. private String dataCreatorColumn = "creator";
  21. /**
  22. * 数据权限id字段名
  23. */
  24. private String dataPermissionIdColumn = "permission_id";
  25. /**
  26. * 需要进行数据权限id过滤的表名集合
  27. */
  28. private List<String> filterTables;
  29. /**
  30. * 需要忽略的多数据权限的表,此配置优先filterTables,若此配置为空则启用filterTables
  31. */
  32. private List<String> ignoreTables;
  33. /**
  34. * 需要排除数据权限过滤的登录用户名
  35. */
  36. private List<String> ignoreLoginNames;
  37. }

步骤二、实现MyDataPermissionHandler接口

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

  1. import com.sky.wsp.mybatis.plus.config.properties.DataPermissionProperties;
  2. import com.sky.wsp.mybatis.plus.plugins.handler.MyDataPermissionHandler;
  3. import com.sky.wsp.mybatis.plus.utils.SecurityContextHolder;
  4. import java.util.List;
  5. /**
  6. * 基于用户组织机构(Org)的数据权限处理类
  7. *
  8. * @author wangshaopeng@talkweb.com.cn
  9. * @Date 2023-01-11
  10. */
  11. public class OrgDataPermissionHandler implements MyDataPermissionHandler {
  12. private final DataPermissionProperties properties;
  13. public OrgDataPermissionHandler(DataPermissionProperties properties) {
  14. this.properties = properties;
  15. }
  16. @Override
  17. public Long getDataCreator() {
  18. // user_id作为creator
  19. return SecurityContextHolder.getUserId();
  20. }
  21. @Override
  22. public String getDataCreatorColumn() {
  23. // user_id作为creator
  24. return properties.getDataCreatorColumn();
  25. }
  26. @Override
  27. public List<Long> getDataPermissionIdSet() {
  28. // org_id作为数据权限
  29. return SecurityContextHolder.getOrgIds();
  30. }
  31. @Override
  32. public String getDataPermissionIdColumn() {
  33. // org_id作为数据权限
  34. return properties.getDataPermissionIdColumn();
  35. }
  36. @Override
  37. public boolean ignoreTable(String tableName) {
  38. //忽略指定用户对数据权限的过滤
  39. List<String> ignoreLoginNames=properties.getIgnoreLoginNames();
  40. String loginName=SecurityContextHolder.getUsername();
  41. if(null!=ignoreLoginNames && ignoreLoginNames.contains(loginName)){
  42. return true;
  43. }
  44. //忽略指定表对数据权限的过滤
  45. List<String> ignoreTables = properties.getIgnoreTables();
  46. if (null != ignoreTables && ignoreTables.contains(tableName)) {
  47. return true;
  48. }
  49. return false;
  50. }
  51. }

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

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

  1. import com.baomidou.mybatisplus.annotation.DbType;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
  4. import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
  5. import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
  6. import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
  7. import com.sky.wsp.mybatis.plus.config.properties.DataPermissionProperties;
  8. import com.sky.wsp.mybatis.plus.config.properties.TenantProperties;
  9. import com.sky.wsp.mybatis.plus.handler.DBMetaObjectHandler;
  10. import com.sky.wsp.mybatis.plus.handler.MultiTenantHandler;
  11. import com.sky.wsp.mybatis.plus.handler.OrgDataPermissionHandler;
  12. import com.sky.wsp.mybatis.plus.plugins.inner.MyDataPermissionInterceptor;
  13. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  14. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  15. import org.springframework.context.annotation.Bean;
  16. import org.springframework.context.annotation.Configuration;
  17. /**
  18. * MybatisPlus配置类
  19. *
  20. * @author wangshaopeng@talkweb.com.cn
  21. * @Date 2023-01-11
  22. */
  23. @Configuration(proxyBeanMethods = false)
  24. @EnableConfigurationProperties({
  25. TenantProperties.class,
  26. DataPermissionProperties.class
  27. })
  28. public class MybatisPlusConfig {
  29. /**
  30. * 单页分页条数限制(默认无限制,参见 插件#handlerLimit 方法)
  31. */
  32. private static final Long MAX_LIMIT = 1000L;
  33. @Bean
  34. public MybatisPlusInterceptor mybatisPlusInterceptor(TenantProperties tenantProperties, DataPermissionProperties dataPermissionProperties) {
  35. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  36. if (Boolean.TRUE.equals(tenantProperties.getEnable())) {
  37. // 启用多租户拦截
  38. interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MultiTenantHandler(tenantProperties)));
  39. }
  40. if (Boolean.TRUE.equals(dataPermissionProperties.getEnable())) {
  41. // 启用数据权限拦截
  42. interceptor.addInnerInterceptor(new MyDataPermissionInterceptor(new OrgDataPermissionHandler(dataPermissionProperties)));
  43. }
  44. // 分页拦截
  45. PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
  46. paginationInterceptor.setMaxLimit(MAX_LIMIT);
  47. interceptor.addInnerInterceptor(paginationInterceptor);
  48. // 乐观锁拦截
  49. interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  50. return interceptor;
  51. }
  52. @Bean
  53. @ConditionalOnMissingBean
  54. public MetaObjectHandler metaObjectHandler() {
  55. return new DBMetaObjectHandler();
  56. }
  57. }

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里进行逻辑判断,跳过拦截
  1. /**
  2. * 使用@InterceptorIgnore注解,忽略多租户拦截 <br/>
  3. * 注解@InterceptorIgnore可以用在Mapper类上,也可以用在方法上
  4. *
  5. * @param id
  6. * @return
  7. */
  8. @InterceptorIgnore(tenantLine = "true")
  9. UserOrgVO myFindByIdNoTenant(@Param(value = "id") Long id);
  1. tenant:
  2. enable: true
  3. column: tenant_id
  4. filterTables:
  5. ignoreTables:
  6. # 不进行多租户拦截的表
  7. - wsp_org
  8. ignoreLoginNames:
  9. # 这里配置了ID,需要使用username的,可在MultiTenantHandler中自己实现判断逻辑
  10. - 99
  11. - 98
  12. data:
  13. permission:
  14. enable: true
  15. dataCreatorColumn: create_by
  16. dataPermissionIdColumn: org_id
  17. filterTables:
  18. ignoreTables:
  19. # 不进行数据鉴权拦截的表
  20. - wsp_org
  21. - wsp_role
  22. ignoreLoginNames:
  23. # 这里配置了ID,需要使用username的,可在OrgDataPermissionHandler中自己实现判断逻辑
  24. - 99
  25. - 98

六、参考

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/407525
推荐阅读
相关标签
  

闽ICP备14008679号