contextHolder = new ThreadLocal<>();
+
+ public static void set(DataPermission dataPermission) {
+ contextHolder.set(dataPermission);
+ }
+
+ public static DataPermission get() {
+ return contextHolder.get();
+ }
+
+ public static void clear() {
+ contextHolder.remove();
+ }
+}
diff --git a/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeAspect.java b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeAspect.java
new file mode 100644
index 0000000..275f43a
--- /dev/null
+++ b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeAspect.java
@@ -0,0 +1,44 @@
+package com.zsc.edu.gateway.framework.mybatisplus;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+
+/**
+ * 数据权限注解切面
+ */
+@Aspect
+@Component
+public class DataScopeAspect {
+
+ /**
+ * 环绕通知,拦截带有 @DataPermission 注解的方法
+ * @param joinPoint
+ * @throws Throwable
+ */
+ @Around("@annotation(DataPermission)()")
+ public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ Method method = signature.getMethod();
+
+ // 获取方法上的 @DataPermission 注解
+ DataPermission dataPermission = method.getAnnotation(DataPermission.class);
+
+ if (dataPermission != null) {
+ // 将注解信息存储在上下文中,供 MyBatis 拦截器使用
+ DataPermissionContext.set(dataPermission);
+ }
+
+ try {
+ // 执行目标方法
+ return joinPoint.proceed();
+ } finally {
+ // 方法执行完毕,清除数据权限上下文,避免内存泄露
+ DataPermissionContext.clear();
+ }
+ }
+}
diff --git a/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeHandler.java b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeHandler.java
new file mode 100644
index 0000000..67adb71
--- /dev/null
+++ b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeHandler.java
@@ -0,0 +1,130 @@
+package com.zsc.edu.gateway.framework.mybatisplus;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
+import com.zsc.edu.gateway.framework.security.SecurityUtil;
+import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.Parenthesis;
+import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
+import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
+import net.sf.jsqlparser.expression.operators.relational.InExpression;
+import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
+import net.sf.jsqlparser.schema.Column;
+import net.sf.jsqlparser.schema.Table;
+
+import java.lang.reflect.Method;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 数据权限拼装逻辑处理
+ *
+ */
+@Slf4j
+public class DataScopeHandler implements MultiDataPermissionHandler {
+
+ /**
+ * 获取数据权限 SQL 片段。
+ * {@link MultiDataPermissionHandler#getSqlSegment(Table, Expression, String)} 方法不能覆盖原有的 where 数据,如果 return 了 null 则表示不追加任何 where 条件
+ *
+ * @param table 所执行的数据库表信息,可以通过此参数获取表名和表别名
+ * @param where 原有的 where 条件信息
+ * @param mappedStatementId Mybatis MappedStatementId 根据该参数可以判断具体执行方法
+ * @return JSqlParser 条件表达式,返回的条件表达式会拼接在原有的表达式后面(不会覆盖原有的表达式)
+ */
+ @Override
+ public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) {
+// try {
+ // 获取当前线程中的数据权限信息
+ DataPermission dataPermission = DataPermissionContext.get();
+ if (Objects.isNull(dataPermission)) {
+ return null;
+ }
+ return buildDataScopeByAnnotation(dataPermission);
+
+ }
+ /**
+ * DataScope注解方式,拼装数据权限
+ * @param dataScope
+ * @return
+ */
+ private Expression buildDataScopeByAnnotation(DataPermission dataScope) {
+ UserDetailsImpl userInfo = SecurityUtil.getUserInfo();
+ if (userInfo == null) {
+ return null;
+ }
+ Set dataScopeDeptIds = userInfo.getDataScopeDeptIds();
+ DataScopeType dataScopeType = userInfo.getRole().getDataScope();
+ // 本人ID
+ Long dataScopeCreateId = userInfo.getId();
+ // 本人部门ID
+ Long deptId = userInfo.getDept().getId();
+ // 表别名
+ String tableAlias = dataScope.tableAlias();
+ // 部门限制范围的字段名称
+ String deptAlias = dataScope.deptAlias();
+ // 本人限制范围的字段名称
+ String userAlias = dataScope.userAlias();
+
+ // 拼装数据权限
+ return switch (dataScopeType) {
+ // 全部数据权限
+ case DATA_SCOPE_ALL -> null;
+ // 本部门数据权限, 构建部门eq表达式
+ case DATA_SCOPE_DEPT -> equalsTo(tableAlias, deptAlias, deptId);
+ // 本部门及以下数据权限,构建部门in表达式
+ case DATA_SCOPE_DEPT_AND_CHILD -> inExpression(tableAlias, deptAlias, dataScopeDeptIds);
+ // 本人数据权限,构建本人eq表达式
+ case DATA_SCOPE_SELF -> equalsTo(tableAlias, userAlias, dataScopeCreateId);
+ };
+ }
+
+ /**
+ * 构建eq表达式
+ * @param tableAlias 表别名
+ * @param itemAlias 字段别名
+ * @param itemId id
+ * @return
+ */
+ private EqualsTo equalsTo(String tableAlias, String itemAlias, Long itemId) {
+ if (Objects.nonNull(itemId)) {
+ EqualsTo equalsTo = new EqualsTo();
+ equalsTo.withLeftExpression(buildColumn(tableAlias, itemAlias));
+ equalsTo.setRightExpression(new LongValue(itemId));
+ return equalsTo;
+ } else {
+ return null;
+ }
+ }
+
+ private InExpression inExpression(String tableAlias, String itemAlias, Set itemIds) {
+ if (!itemIds.isEmpty()) {
+ InExpression deptIdInExpression = new InExpression();
+ ParenthesedExpressionList deptIds = new ParenthesedExpressionList<>(itemIds.stream().map(LongValue::new).collect(Collectors.toList()));
+ deptIdInExpression.withLeftExpression(buildColumn(tableAlias, itemAlias));
+ deptIdInExpression.setRightExpression(deptIds);
+ return deptIdInExpression;
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * 构建Column
+ *
+ * @param tableAlias 表别名
+ * @param columnName 字段名称
+ * @return 带表别名字段
+ */
+ public static Column buildColumn(String tableAlias, String columnName) {
+ if (StringUtils.isNotEmpty(tableAlias)) {
+ columnName = tableAlias + "." + columnName;
+ }
+ return new Column(columnName);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeType.java b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeType.java
new file mode 100644
index 0000000..6673eed
--- /dev/null
+++ b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/DataScopeType.java
@@ -0,0 +1,36 @@
+package com.zsc.edu.gateway.framework.mybatisplus;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+public enum DataScopeType implements IEnum {
+ /**
+ * 全部数据权限
+ */
+ DATA_SCOPE_ALL(1),
+ /**
+ * 部门数据权限
+ */
+ DATA_SCOPE_DEPT(2),
+ /**
+ * 部门及以下数据权限
+ */
+ DATA_SCOPE_DEPT_AND_CHILD(3),
+ /**
+ * 仅个人数据权限
+ */
+ DATA_SCOPE_SELF(4);
+ /**
+ * 自定义数据权限
+ */
+// DATA_SCOPE_CUSTOM(5);
+
+ private final int value;
+
+ @Override
+ public Integer getValue() {
+ return this.value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/MybatisPlusConfig.java b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/MybatisPlusConfig.java
index 42fc7db..2d9898d 100644
--- a/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/MybatisPlusConfig.java
+++ b/src/main/java/com/zsc/edu/gateway/framework/mybatisplus/MybatisPlusConfig.java
@@ -2,7 +2,9 @@ package com.zsc.edu.gateway.framework.mybatisplus;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -13,18 +15,15 @@ import org.springframework.context.annotation.Configuration;
@MapperScan(basePackages = "com.zsc.edu.gateway.modules.**.repo")
@Configuration
public class MybatisPlusConfig {
-
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ // 添加数据权限插件
+ DataPermissionInterceptor dataPermissionInterceptor = new DataPermissionInterceptor(new DataScopeHandler());
+ // 添加自定义的数据权限处理器
+ interceptor.addInnerInterceptor(dataPermissionInterceptor);
+ // 添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
-// // 添加数据权限插件
-// MyDataPermissionInterceptor dataPermissionInterceptor = new MyDataPermissionInterceptor();
-// // 添加自定义的数据权限处理器
-// dataPermissionInterceptor.setDataPermissionHandler(new MyDataPermissionHandler());
-// interceptor.addInnerInterceptor(dataPermissionInterceptor);
return interceptor;
}
-
-
}
diff --git a/src/main/java/com/zsc/edu/gateway/framework/security/JpaUserDetailsServiceImpl.java b/src/main/java/com/zsc/edu/gateway/framework/security/JpaUserDetailsServiceImpl.java
index 6331ec7..6294330 100644
--- a/src/main/java/com/zsc/edu/gateway/framework/security/JpaUserDetailsServiceImpl.java
+++ b/src/main/java/com/zsc/edu/gateway/framework/security/JpaUserDetailsServiceImpl.java
@@ -1,6 +1,8 @@
package com.zsc.edu.gateway.framework.security;
+import com.zsc.edu.gateway.common.util.TreeUtil;
import com.zsc.edu.gateway.exception.StateException;
+import com.zsc.edu.gateway.modules.system.entity.Dept;
import com.zsc.edu.gateway.modules.system.entity.Menu;
import com.zsc.edu.gateway.modules.system.entity.RoleAuthority;
import com.zsc.edu.gateway.modules.system.entity.User;
@@ -8,6 +10,7 @@ import com.zsc.edu.gateway.modules.system.repo.AuthorityRepository;
import com.zsc.edu.gateway.modules.system.repo.MenuRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleAuthoritiesRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
+import com.zsc.edu.gateway.modules.system.service.DeptService;
import lombok.AllArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -27,9 +30,9 @@ import java.util.stream.Collectors;
public class JpaUserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepo;
-// private final RoleAuthoritiesRepository roleAuthoritiesRepository;
private final AuthorityRepository authorityRepository;
private final MenuRepository menuRepository;
+ private final DeptService deptService;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -38,7 +41,10 @@ public class JpaUserDetailsServiceImpl implements UserDetailsService {
if (!user.getEnableState()) {
throw new StateException("用户 '" + username + "' 已被禁用!请联系管理员");
}
-
+ List depts = deptService.listTree(user.deptId);
+ List flat = TreeUtil.flat(depts, Dept::getChildren, d -> d.setChildren(null));
+ Set dataScopeDeptIds = flat.stream().map(Dept::getId).collect(Collectors.toSet());
+ user.setDataScopeDeptIds(dataScopeDeptIds);
// List roleAuthorities= roleAuthoritiesRepository.selectByRoleId(user.getRoleId());
// user.role.authorities = authorityRepository.selectAuthoritiesByRoleId(user.getRoleId());
List