一、${params.datascope}是什麼?
${params.datascope}是一種限制數據訪問範圍的機制。例如,在多租戶系統中,不同的租戶在系統內共享相同的資源,但是他們只能訪問他們自己的數據。
使用${params.datascope}可以保護系統內敏感數據的隱私性,減少數據泄露的風險。${params.datascope}常用於管理後台、多租戶系統、雲計算等方面。
二、${params.datascope}的實現方式
${params.datascope}的實現方式多種多樣,以下是幾種常見的實現方式:
1. 基於註解的${params.datascope}
/**
* 訂單Mapper
*/
@Mapper
public interface OrderMapper {
/**
* 根據用戶ID查詢訂單列表
*
* @param userId 用戶ID
* @return 訂單列表
*/
@Select("SELECT id, order_no FROM order WHERE user_id = #{userId} ${@com.example.plugin.DataScope()}")
List<Order> listByUserId(Long userId);
}
/**
* ${params.datascope}註解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataScope {
/**
* 是否限制數據
*/
boolean limit() default true;
/**
* 數據範圍表別名
*/
String alias() default "t";
/**
* 部門ID列表
*/
String[] deptIds() default {};
}
使用${params.datascope}註解,可以在SQL語句中自動生成數據範圍限制條件。註解中的limit屬性用於控制是否限制數據,deptIds屬性用於指定允許訪問的部門ID列表。
2. 基於AOP的${params.datascope}
/**
* ${params.datascope}切面
*/
@Aspect
@Component
public class DataScopeAspect {
private final ThreadLocal dataScopeThreadLocal = new ThreadLocal();
/**
* ${params.datascope}切點
*/
@Pointcut("@annotation(com.example.plugin.DataScope)")
public void dataScopePointCut() {}
/**
* 前置增強
*/
@Before("dataScopePointCut()")
public void before(JoinPoint point) {
//獲取${params.datascope}註解
DataScope dataScope = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(DataScope.class);
if (dataScope != null) {
//將${params.datascope}註解存入ThreadLocal
dataScopeThreadLocal.set(dataScope);
}
}
/**
* 後置增強
*/
@After("dataScopePointCut()")
public void after() {
//清理ThreadLocal
dataScopeThreadLocal.remove();
}
/**
* 環繞增強
*/
@Around("dataScopePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
//獲取${params.datascope}註解
DataScope dataScope = dataScopeThreadLocal.get();
if (dataScope != null && dataScope.limit()) {
//生成數據範圍限制SQL語句
String sql = generateSql(dataScope.alias(), dataScope.deptIds());
//修改原有SQL語句,添加數據範圍限制條件
MetaObject metaObject = SystemMetaObject.forObject(point.getTarget());
MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
String originSql = boundSql.getSql();
String newSql = String.join(" ", originSql, sql);
metaObject.setValue("delegate.boundSql.sql", newSql);
}
//執行原有方法
return point.proceed();
}
/**
* 生成數據範圍限制SQL語句
*/
private String generateSql(String alias, String[] deptIds) {
StringBuilder sb = new StringBuilder();
sb.append("AND ").append(alias).append(".dept_id IN (");
for (String deptId : deptIds) {
sb.append("'").append(deptId).append("',");
}
sb.setLength(sb.length() - 1);
sb.append(")");
return sb.toString();
}
}
使用AOP織入的方式,可以將${params.datascope}實現的邏輯抽離出來,避免了代碼的重複編寫並提高了代碼的重用性。
3. 基於自定義SQL攔截器的${params.datascope}
/**
* ${params.datascope}攔截器
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class DataScopeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
//獲取SQL
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
String originSql = boundSql.getSql();
//獲取${params.datascope}註解
DataScope dataScope = DataScopeUtils.getDataScope();
if (dataScope != null && dataScope.limit()) {
//生成數據範圍限制SQL語句
String sql = generateSql(dataScope.alias(), dataScope.deptIds());
//修改原有SQL語句,添加數據範圍限制條件
String newSql = String.join(" ", originSql, sql);
SystemMetaObject.forObject(boundSql).setValue("sql", newSql);
}
//執行原有方法
return invocation.proceed();
}
/**
* 生成數據範圍限制SQL語句
*/
private String generateSql(String alias, String[] deptIds) {
StringBuilder sb = new StringBuilder();
sb.append("AND ").append(alias).append(".dept_id IN (");
for (String deptId : deptIds) {
sb.append("'").append(deptId).append("',");
}
sb.setLength(sb.length() - 1);
sb.append(")");
return sb.toString();
}
}
自定義SQL攔截器是一種通用的實現${params.datascope}的方式,但是需要考慮攔截器順序等問題,實現起來比較複雜。
三、${params.datascope}的優缺點
優點
1. 可以保護系統內敏感數據的隱私性,減少數據泄露的風險;
2. 可以提高系統的安全性和穩定性;
3. 可以提高代碼的靈活性和可維護性,便於代碼的擴展和維護。
缺點
1. ${params.datascope}實現的複雜度較高,需要考慮註解、AOP、自定義SQL攔截器等多種實現方式;
2. ${params.datascope}往往需要與其他機制(如RBAC、OAuth2等)配合使用,增加了集成難度;
3. 當數據範圍較大時,會影響系統的性能。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/286358.html