mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
Merge branch 'main' of https://gitee.com/mybatis-flex/mybatis-flex
This commit is contained in:
commit
f811c56a24
@ -49,7 +49,7 @@ MaskManager.registerMaskProcesser("自定义规则名称"
|
|||||||
```
|
```
|
||||||
|
|
||||||
2、使用自定义的脱敏规则
|
2、使用自定义的脱敏规则
|
||||||
```java 7
|
```java
|
||||||
@Table("tb_account")
|
@Table("tb_account")
|
||||||
public class Account {
|
public class Account {
|
||||||
|
|
||||||
@ -66,19 +66,47 @@ public class Account {
|
|||||||
在某些场景下,程序希望查询得到的数据是原始数据,而非脱敏数据。比如要去查询用户的手机号,然后给用户发送短信。又或者说,我们进入编辑页面编辑用户数据,
|
在某些场景下,程序希望查询得到的数据是原始数据,而非脱敏数据。比如要去查询用户的手机号,然后给用户发送短信。又或者说,我们进入编辑页面编辑用户数据,
|
||||||
如果编辑页面展示的是脱敏数据,然后再次点击保存,那么数据库的真实数据也会被脱敏覆盖。
|
如果编辑页面展示的是脱敏数据,然后再次点击保存,那么数据库的真实数据也会被脱敏覆盖。
|
||||||
|
|
||||||
因此,MaskManager 提供了 `skipMask`、`restoreMask` 两个方法来处理这种场景:
|
因此,MaskManager 提供了 `withoutMask`、`skipMask`、`restoreMask` 三个方法来处理这种场景:
|
||||||
|
|
||||||
```java 2,7
|
推荐使用`withoutMask`方法,该方法使用了模版方法设计模式,保障跳过脱敏处理并执行相关逻辑后自动恢复脱敏处理。
|
||||||
|
|
||||||
|
`withoutMask`方法实现如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static <T> T withoutMask(Supplier<T> supplier) {
|
||||||
|
try {
|
||||||
|
skipMask();
|
||||||
|
return supplier.get();
|
||||||
|
} finally {
|
||||||
|
restoreMask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
AccountMapper mapper = ...;
|
||||||
|
List<Account> accounts = MaskManager.withoutMask(mapper::selectAll);
|
||||||
|
System.out.println(accounts);
|
||||||
|
```
|
||||||
|
|
||||||
|
`skipMask`和`restoreMask`方法需配套使用,推荐使用`try{...}finally{...}`模式,如下例所示。
|
||||||
|
使用这两个方法可以自主控制跳过脱敏处理和恢复脱敏处理的时机。
|
||||||
|
当跳过脱敏处理和恢复脱敏处理无法放在同一个方法中时,可以使用这两个方法。
|
||||||
|
此时需要仔细处理代码分支及异常,以防止跳过脱敏处理后未恢复脱敏处理,导致安全隐患。
|
||||||
|
|
||||||
|
```java
|
||||||
try {
|
try {
|
||||||
MaskManager.skipMask()
|
MaskManager.skipMask();
|
||||||
|
|
||||||
//此处查询到的数据不会进行脱敏处理
|
//此处查询到的数据不会进行脱敏处理
|
||||||
accountMapper.selectListByQuery(...)
|
accountMapper.selectListByQuery(...);
|
||||||
} finally {
|
} finally {
|
||||||
MaskManager.restoreMask()
|
MaskManager.restoreMask();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
::: tip 提示
|
::: tip 提示
|
||||||
在具体的应用中,我们通常会把 `skipMask()` 和 `restoreMask()` 放到统一的拦截器里,对某一类业务进行统一拦截和处理。
|
在具体的应用中,我们通常会把`withoutMask`、`skipMask()` 和 `restoreMask()` 放到统一的拦截器里,对某一类业务进行统一拦截和处理。
|
||||||
:::
|
:::
|
||||||
|
|||||||
@ -111,16 +111,42 @@ DELETE FROM tb_article where id = ? and tenant_id in (?, ?, ?)
|
|||||||
|
|
||||||
### 忽略租户条件
|
### 忽略租户条件
|
||||||
|
|
||||||
在某些场景下,在增删改查等操作,我们可能需要忽略租户条件,此时可以使用如下代码:
|
在某些场景下,在增删改查等操作,我们可能需要忽略租户条件,
|
||||||
|
此时可以使用TenantManager的`withoutTenantCondition`、`ignoreTenantCondition`、`restoreTenantCondition`三个方法。
|
||||||
|
|
||||||
|
推荐使用`withoutTenantCondition`方法,该方法使用了模版方法设计模式,保障忽略 tenant 条件并执行相关逻辑后自动恢复 tenant 条件。
|
||||||
|
|
||||||
|
`withoutTenantCondition`方法实现如下:
|
||||||
|
```java
|
||||||
|
public static <T> T withoutTenantCondition(Supplier<T> supplier) {
|
||||||
|
try {
|
||||||
|
ignoreTenantCondition();
|
||||||
|
return supplier.get();
|
||||||
|
} finally {
|
||||||
|
restoreTenantCondition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
使用方法:
|
||||||
|
```java
|
||||||
|
TenantAccountMapper mapper = ...;
|
||||||
|
List<TenantAccount> tenantAccounts = TenantManager.withoutTenantCondition(mapper::selectAll);
|
||||||
|
System.out.println(tenantAccounts);
|
||||||
|
```
|
||||||
|
|
||||||
|
`ignoreTenantCondition`和`restoreTenantCondition`方法需配套使用,推荐使用`try{...}finally{...}`模式,如下例所示。
|
||||||
|
使用这两个方法可以自主控制忽略 tenant 条件和恢复 tenant 条件的时机。
|
||||||
|
当忽略 tenant 条件和恢复 tenant 条件无法放在同一个方法中时,可以使用这两个方法。
|
||||||
|
此时需要仔细处理代码分支及异常,以防止忽略 tenant 条件后未恢复 tenant 条件,导致数据异常。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
try {
|
try {
|
||||||
TenantManager.ignoreTenantCondition()
|
TenantManager.ignoreTenantCondition();
|
||||||
|
|
||||||
//此处操作的数据不会带有 tenant_id 的条件
|
//此处操作的数据不会带有 tenant_id 的条件
|
||||||
accountMapper.selectListByQuery(...)
|
accountMapper.selectListByQuery(...);
|
||||||
} finally {
|
} finally {
|
||||||
TenantManager.restoreTenantCondition()
|
TenantManager.restoreTenantCondition();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package com.mybatisflex.core.mask;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据脱敏工厂类
|
* 数据脱敏工厂类
|
||||||
@ -56,6 +57,18 @@ public class MaskManager {
|
|||||||
|
|
||||||
private static ThreadLocal<Boolean> skipFlags = new ThreadLocal<>();
|
private static ThreadLocal<Boolean> skipFlags = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳过脱敏处理
|
||||||
|
*/
|
||||||
|
public static <T> T withoutMask(Supplier<T> supplier) {
|
||||||
|
try {
|
||||||
|
skipMask();
|
||||||
|
return supplier.get();
|
||||||
|
} finally {
|
||||||
|
restoreMask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳过脱敏处理
|
* 跳过脱敏处理
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.mybatisflex.core.tenant;
|
package com.mybatisflex.core.tenant;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class TenantManager {
|
public class TenantManager {
|
||||||
|
|
||||||
private static ThreadLocal<Boolean> ignoreFlags = new ThreadLocal<>();
|
private static ThreadLocal<Boolean> ignoreFlags = new ThreadLocal<>();
|
||||||
@ -29,6 +31,18 @@ public class TenantManager {
|
|||||||
TenantManager.tenantFactory = tenantFactory;
|
TenantManager.tenantFactory = tenantFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略 tenant 条件
|
||||||
|
*/
|
||||||
|
public static <T> T withoutTenantCondition(Supplier<T> supplier) {
|
||||||
|
try {
|
||||||
|
ignoreTenantCondition();
|
||||||
|
return supplier.get();
|
||||||
|
} finally {
|
||||||
|
restoreTenantCondition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 忽略 tenant 条件
|
* 忽略 tenant 条件
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.mybatisflex.test;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||||
|
import com.mybatisflex.core.mask.MaskManager;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MaskManagerTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
|
.setName("db1")
|
||||||
|
.addScript("schema.sql")
|
||||||
|
.addScript("data.sql")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MybatisFlexBootstrap.getInstance()
|
||||||
|
.setDataSource(dataSource)
|
||||||
|
.addMapper(AccountMapper.class)
|
||||||
|
.start();
|
||||||
|
|
||||||
|
//获取 mapper
|
||||||
|
AccountMapper mapper = MybatisFlexBootstrap.getInstance().getMapper(AccountMapper.class);
|
||||||
|
List<Account> accounts = mapper.selectAll();
|
||||||
|
// List<Account> accounts = MaskManager.withoutMask(mapper::selectAll);
|
||||||
|
System.out.println(accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -59,4 +59,15 @@ public class TenantAccount{
|
|||||||
public void setTenantId(Long tenantId) {
|
public void setTenantId(Long tenantId) {
|
||||||
this.tenantId = tenantId;
|
this.tenantId = tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TenantAccount{" +
|
||||||
|
"id=" + id +
|
||||||
|
", userName='" + userName + '\'' +
|
||||||
|
", age=" + age +
|
||||||
|
", birthday=" + birthday +
|
||||||
|
", tenantId=" + tenantId +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.mybatisflex.test;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||||
|
import com.mybatisflex.core.audit.AuditManager;
|
||||||
|
import com.mybatisflex.core.audit.ConsoleMessageCollector;
|
||||||
|
import com.mybatisflex.core.tenant.TenantFactory;
|
||||||
|
import com.mybatisflex.core.tenant.TenantManager;
|
||||||
|
import com.mybatisflex.mapper.TenantAccountMapper;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TenantManagerTester {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
|
.addScript("schema03.sql")
|
||||||
|
.addScript("data03.sql")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MybatisFlexBootstrap.getInstance()
|
||||||
|
.setDataSource(dataSource)
|
||||||
|
.addMapper(TenantAccountMapper.class)
|
||||||
|
.start();
|
||||||
|
|
||||||
|
//输出日志
|
||||||
|
AuditManager.setAuditEnable(true);
|
||||||
|
AuditManager.setMessageCollector(new ConsoleMessageCollector());
|
||||||
|
|
||||||
|
//配置 tenantFactory
|
||||||
|
TenantManager.setTenantFactory(new TenantFactory() {
|
||||||
|
@Override
|
||||||
|
public Object[] getTenantIds() {
|
||||||
|
return new Object[]{1};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TenantAccountMapper mapper = MybatisFlexBootstrap.getInstance().getMapper(TenantAccountMapper.class);
|
||||||
|
List<TenantAccount> tenantAccounts = TenantManager.withoutTenantCondition(mapper::selectAll);
|
||||||
|
System.out.println(tenantAccounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user