feat: 新增mybatis-plus数据权限拦截器

This commit is contained in:
haoxr
2022-12-13 00:29:17 +08:00
parent 919fe181e2
commit 33327f48a9
5 changed files with 210 additions and 5 deletions

View File

@@ -0,0 +1,30 @@
package com.youlai.system.common.annotation;
import java.lang.annotation.*;
/**
* MP数据权限注解
* <p>
* https://gitee.com/baomidou/mybatis-plus/issues/I37I90
*
* @author <a href="mailto:2256222053@qq.com">zc</a>
* @date 2021-12-10
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DataPermission {
/**
* 数据权限 {@link com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor}
*/
String deptAlias() default "";
String deptIdColumnName() default "dept_id";
String userAlias() default "";
String userIdColumnName() default "create_by";
}

View File

@@ -4,11 +4,9 @@ import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.youlai.system.handler.IntegerArrayJsonTypeHandler;
import com.youlai.system.handler.LongArrayJsonTypeHandler;
import com.youlai.system.handler.MyMetaObjectHandler;
import com.youlai.system.handler.StringArrayJsonTypeHandler;
import com.youlai.system.handler.*;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.context.annotation.Bean;
@@ -16,7 +14,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* MP配置类
* Mybatis-Plus配置类
*
* @author haoxr
* @date 2022/7/2
@@ -31,6 +29,8 @@ public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//数据权限
interceptor.addInnerInterceptor(new DataPermissionInterceptor(new MyDataPermissionHandler()));
//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

View File

@@ -0,0 +1,32 @@
package com.youlai.system.enums;
import com.youlai.system.common.base.IBaseEnum;
import lombok.Getter;
/**
* 数据权限枚举
*
* @author haoxr
* @date 2022/10/14
*/
public enum DataScopeEnum implements IBaseEnum<Integer> {
/**
* value 越小,数据权限范围越大
*/
ALL(0, "所有数据"),
DEPT_AND_SUB(1, "部门及子部门数据"),
DEPT(2, "本部门数据"),
SELF(3, "本人数据");
@Getter
private Integer value;
@Getter
private String label;
DataScopeEnum(Integer value, String label) {
this.value = value;
this.label = label;
}
}

View File

@@ -0,0 +1,101 @@
package com.youlai.system.handler;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.youlai.system.common.annotation.DataPermission;
import com.youlai.system.common.base.IBaseEnum;
import com.youlai.system.enums.DataScopeEnum;
import com.youlai.system.util.SecurityUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import java.lang.reflect.Method;
/**
* 数据权限控制器
*
* @author zc
* @date 2021-12-10 13:28
*/
@Slf4j
public class MyDataPermissionHandler implements DataPermissionHandler {
@Override
@SneakyThrows
public Expression getSqlSegment(Expression where, String mappedStatementId) {
// 超级管理员不受数据权限控制
if (SecurityUtils.isRoot()) {
return where;
}
Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(StringPool.DOT)));
String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(StringPool.DOT) + 1);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
DataPermission annotation = method.getAnnotation(DataPermission.class);
if (ObjectUtils.isNotEmpty(annotation)
&& (method.getName().equals(methodName) || (method.getName() + "_COUNT").equals(methodName))) {
return dataScopeFilter(annotation.deptAlias(), annotation.deptIdColumnName(), annotation.userAlias(), annotation.userIdColumnName(), where);
}
}
return where;
}
/**
* 构建过滤条件
*
* @param where 当前查询条件
* @return 构建后查询条件
*/
@SneakyThrows
public static Expression dataScopeFilter(String deptAlias, String deptIdColumnName, String userAlias, String userIdColumnName, Expression where) {
String deptColumnName = StrUtil.isNotBlank(deptAlias) ? (deptAlias +StringPool.DOT+ deptIdColumnName) : deptIdColumnName;
String userColumnName = StrUtil.isNotBlank(userAlias) ? (userAlias + StringPool.DOT + userIdColumnName) : userIdColumnName;
// 获取当前用户的数据权限
Integer dataScope = SecurityUtils.getDataScope();
DataScopeEnum dataScopeEnum = IBaseEnum.getEnumByValue(dataScope, DataScopeEnum.class);
Long deptId, userId;
String appendSqlStr;
switch (dataScopeEnum) {
case ALL:
return where;
case DEPT:
deptId = SecurityUtils.getDeptId();
appendSqlStr = deptColumnName + StringPool.EQUALS+ deptId;
break;
case SELF:
userId = SecurityUtils.getUserId();
appendSqlStr = userColumnName + StringPool.EQUALS + userId;
break;
// 默认部门及子部门数据权限
default:
deptId = SecurityUtils.getDeptId();
appendSqlStr = deptColumnName + " IN ( SELECT id FROM sys_dept WHERE id = " + deptId + " or find_in_set( " + deptId + " , tree_path ) )";
break;
}
if (StrUtil.isBlank(appendSqlStr)) {
return where;
}
Expression appendExpression =CCJSqlParserUtil.parseCondExpression(appendSqlStr);
if(where==null){
return appendExpression;
}
return new AndExpression(where, appendExpression);
}
}

View File

@@ -0,0 +1,42 @@
package com.youlai.system.security.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.youlai.system.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.PatternMatchUtils;
import java.util.Set;
@Service("pms")
@RequiredArgsConstructor
public class PermissionService {
private final RedisTemplate redisTemplate;
public boolean hasPermission(String perm) {
if (StrUtil.isBlank(perm)) {
return false;
}
if (SecurityUtils.isRoot()) {
return true;
}
Long userId = SecurityUtils.getUserId();
Set<String> perms = (Set<String>) redisTemplate.opsForValue().get("USER_PERMS:" + userId);
if (CollectionUtil.isEmpty(perms)) {
return false;
}
boolean hasPermission = perms.stream()
.anyMatch(item -> PatternMatchUtils.simpleMatch(perm, item));
return hasPermission;
}
}