This commit is contained in:
开源海哥 2023-05-11 11:34:35 +08:00
commit f811c56a24
7 changed files with 182 additions and 11 deletions

View File

@ -49,7 +49,7 @@ MaskManager.registerMaskProcesser("自定义规则名称"
```
2、使用自定义的脱敏规则
```java 7
```java
@Table("tb_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 {
MaskManager.skipMask()
MaskManager.skipMask();
//此处查询到的数据不会进行脱敏处理
accountMapper.selectListByQuery(...)
accountMapper.selectListByQuery(...);
} finally {
MaskManager.restoreMask()
MaskManager.restoreMask();
}
```
::: tip 提示
在具体的应用中,我们通常会把 `skipMask()``restoreMask()` 放到统一的拦截器里,对某一类业务进行统一拦截和处理。
在具体的应用中,我们通常会把`withoutMask``skipMask()``restoreMask()` 放到统一的拦截器里,对某一类业务进行统一拦截和处理。
:::

View File

@ -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
try {
TenantManager.ignoreTenantCondition()
TenantManager.ignoreTenantCondition();
//此处操作的数据不会带有 tenant_id 的条件
accountMapper.selectListByQuery(...)
accountMapper.selectListByQuery(...);
} finally {
TenantManager.restoreTenantCondition()
TenantManager.restoreTenantCondition();
}
```

View File

@ -17,6 +17,7 @@ package com.mybatisflex.core.mask;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
/**
* 数据脱敏工厂类
@ -56,6 +57,18 @@ public class MaskManager {
private static ThreadLocal<Boolean> skipFlags = new ThreadLocal<>();
/**
* 跳过脱敏处理
*/
public static <T> T withoutMask(Supplier<T> supplier) {
try {
skipMask();
return supplier.get();
} finally {
restoreMask();
}
}
/**
* 跳过脱敏处理
*/

View File

@ -15,6 +15,8 @@
*/
package com.mybatisflex.core.tenant;
import java.util.function.Supplier;
public class TenantManager {
private static ThreadLocal<Boolean> ignoreFlags = new ThreadLocal<>();
@ -29,6 +31,18 @@ public class TenantManager {
TenantManager.tenantFactory = tenantFactory;
}
/**
* 忽略 tenant 条件
*/
public static <T> T withoutTenantCondition(Supplier<T> supplier) {
try {
ignoreTenantCondition();
return supplier.get();
} finally {
restoreTenantCondition();
}
}
/**
* 忽略 tenant 条件

View File

@ -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);
}
}

View File

@ -59,4 +59,15 @@ public class TenantAccount{
public void setTenantId(Long tenantId) {
this.tenantId = tenantId;
}
@Override
public String toString() {
return "TenantAccount{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
", birthday=" + birthday +
", tenantId=" + tenantId +
'}';
}
}

View File

@ -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);
}
}