一、${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/n/286358.html