diff --git a/src/main/java/com/youlai/system/common/annotation/DataPermission.java b/src/main/java/com/youlai/system/common/annotation/DataPermission.java new file mode 100644 index 00000000..eab09bdb --- /dev/null +++ b/src/main/java/com/youlai/system/common/annotation/DataPermission.java @@ -0,0 +1,30 @@ +package com.youlai.system.common.annotation; + +import java.lang.annotation.*; + +/** + * MP数据权限注解 + *

+ * https://gitee.com/baomidou/mybatis-plus/issues/I37I90 + * + * @author zc + * @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"; + +} + diff --git a/src/main/java/com/youlai/system/config/MybatisPlusConfig.java b/src/main/java/com/youlai/system/config/MybatisPlusConfig.java index 095bf2e3..b7ee3733 100644 --- a/src/main/java/com/youlai/system/config/MybatisPlusConfig.java +++ b/src/main/java/com/youlai/system/config/MybatisPlusConfig.java @@ -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)); diff --git a/src/main/java/com/youlai/system/enums/DataScopeEnum.java b/src/main/java/com/youlai/system/enums/DataScopeEnum.java new file mode 100644 index 00000000..d2dd732f --- /dev/null +++ b/src/main/java/com/youlai/system/enums/DataScopeEnum.java @@ -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 { + + /** + * 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; + } +} diff --git a/src/main/java/com/youlai/system/handler/MyDataPermissionHandler.java b/src/main/java/com/youlai/system/handler/MyDataPermissionHandler.java new file mode 100644 index 00000000..a188397d --- /dev/null +++ b/src/main/java/com/youlai/system/handler/MyDataPermissionHandler.java @@ -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); + } + + +} + diff --git a/src/main/java/com/youlai/system/security/service/PermissionService.java b/src/main/java/com/youlai/system/security/service/PermissionService.java new file mode 100644 index 00000000..579ba1c3 --- /dev/null +++ b/src/main/java/com/youlai/system/security/service/PermissionService.java @@ -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 perms = (Set) redisTemplate.opsForValue().get("USER_PERMS:" + userId); + + if (CollectionUtil.isEmpty(perms)) { + return false; + } + boolean hasPermission = perms.stream() + .anyMatch(item -> PatternMatchUtils.simpleMatch(perm, item)); + return hasPermission; + } + + +}