Sfoglia il codice sorgente

pms 设备表添加设备责任人数据权限

zhangcl 1 settimana fa
parent
commit
a8bd993ecc

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DevicePersonDataPermissionConfiguration.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.datapermission.config;
+
+import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
+import cn.iocoder.yudao.framework.datapermission.core.rule.device.DevicePersonDataPermissionRule;
+import cn.iocoder.yudao.framework.security.core.LoginUser;
+import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+
+@AutoConfiguration
+@ConditionalOnClass(LoginUser.class)
+@ConditionalOnBean(value = {PermissionApi.class, DeptDataPermissionRuleCustomizer.class})
+public class DevicePersonDataPermissionConfiguration {
+
+    @Bean
+    public DevicePersonDataPermissionRule devicePersonDataPermissionRule(PermissionApi permissionApi) {
+        return new DevicePersonDataPermissionRule(permissionApi);
+    }
+}

+ 38 - 1
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionRuleHandler.java

@@ -7,9 +7,12 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
 import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
 import lombok.RequiredArgsConstructor;
 import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.Parenthesis;
 import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
 import net.sf.jsqlparser.schema.Table;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -33,6 +36,9 @@ public class DataPermissionRuleHandler implements MultiDataPermissionHandler {
             return null;
         }
 
+        // 收集所有权限条件
+        List<Expression> permissionExpressions = new ArrayList<>();
+
         // 生成条件
         Expression allExpression = null;
         for (DataPermissionRule rule : rules) {
@@ -46,12 +52,43 @@ public class DataPermissionRuleHandler implements MultiDataPermissionHandler {
             Expression oneExpress = rule.getExpression(tableName, table.getAlias());
             if (oneExpress == null) {
                 continue;
+            } else {
+                permissionExpressions.add(oneExpress);
             }
             // 拼接到 allExpression 中
             allExpression = allExpression == null ? oneExpress
                     : new AndExpression(allExpression, oneExpress);
         }
-        return allExpression;
+        // 如果没有权限条件,返回 null
+        if (permissionExpressions.isEmpty()) {
+            return null;
+        }
+        // 组合权限条件:使用 OR 连接所有条件
+        Expression combinedPermission = combineExpressionsWithOr(permissionExpressions);
+
+        // 将组合条件用括号括起来
+        return new Parenthesis(combinedPermission);
+    }
+
+    /**
+     * 使用 OR 连接多个表达式
+     */
+    private Expression combineExpressionsWithOr(List<Expression> expressions) {
+        if (expressions.isEmpty()) {
+            return null;
+        }
+
+        // 如果只有一个表达式,直接返回
+        if (expressions.size() == 1) {
+            return expressions.get(0);
+        }
+
+        // 使用 OR 连接多个表达式
+        Expression combined = expressions.get(0);
+        for (int i = 1; i < expressions.size(); i++) {
+            combined = new OrExpression(combined, expressions.get(i));
+        }
+        return combined;
     }
 
 }

+ 21 - 7
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImpl.java

@@ -2,12 +2,13 @@ package cn.iocoder.yudao.framework.datapermission.core.rule;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
 import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder;
+import cn.iocoder.yudao.framework.datapermission.core.rule.device.DevicePersonDataPermissionRule;
 import lombok.RequiredArgsConstructor;
 
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -31,32 +32,45 @@ public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory
 
     @Override // mappedStatementId 参数,暂时没有用。以后,可以基于 mappedStatementId + DataPermission 进行缓存
     public List<DataPermissionRule> getDataPermissionRule(String mappedStatementId) {
+        // 获取所有可用规则(包括责任人规则)
+        List<DataPermissionRule> allAvailableRules = getAllRules();
         // 1. 无数据权限
-        if (CollUtil.isEmpty(rules)) {
+        if (CollUtil.isEmpty(allAvailableRules)) {
             return Collections.emptyList();
         }
         // 2. 未配置,则默认开启
         DataPermission dataPermission = DataPermissionContextHolder.get();
         if (dataPermission == null) {
-            return rules;
+            return allAvailableRules;
         }
         // 3. 已配置,但禁用
         if (!dataPermission.enable()) {
             return Collections.emptyList();
         }
 
+        List<DataPermissionRule> result = new ArrayList<>();
         // 4. 已配置,只选择部分规则
         if (ArrayUtil.isNotEmpty(dataPermission.includeRules())) {
             return rules.stream().filter(rule -> ArrayUtil.contains(dataPermission.includeRules(), rule.getClass()))
-                    .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询
+                    .collect(Collectors.toList());
+            // 一般规则不会太多,所以不采用 HashSet 查询
         }
         // 5. 已配置,只排除部分规则
         if (ArrayUtil.isNotEmpty(dataPermission.excludeRules())) {
             return rules.stream().filter(rule -> !ArrayUtil.contains(dataPermission.excludeRules(), rule.getClass()))
-                    .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询
+                    .collect(Collectors.toList());
+            // 一般规则不会太多,所以不采用 HashSet 查询
         }
         // 6. 已配置,全部规则
-        return rules;
+
+        // 7. 添加责任人规则(优先级最低)
+        return new ArrayList<>(allAvailableRules);
+    }
+
+    private List<DataPermissionRule> getAllRules() {
+        Set<DataPermissionRule> allRules = new LinkedHashSet<>(rules);
+        allRules.addAll(SpringUtils.getBeansOfType(DevicePersonDataPermissionRule.class).values());
+        return new ArrayList<>(allRules);
     }
 
 }

+ 120 - 0
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/device/DevicePersonDataPermissionRule.java

@@ -0,0 +1,120 @@
+package cn.iocoder.yudao.framework.datapermission.core.rule.device;
+
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
+import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule;
+import cn.iocoder.yudao.framework.security.core.LoginUser;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
+import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
+import lombok.AllArgsConstructor;
+import net.sf.jsqlparser.expression.Alias;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+
+import java.util.Collections;
+import java.util.Set;
+
+@AllArgsConstructor
+public class DevicePersonDataPermissionRule implements DataPermissionRule {
+
+    /**
+     * LoginUser 的 Context 缓存 Key
+     */
+    protected static final String CONTEXT_KEY = DeptDataPermissionRule.class.getSimpleName();
+
+    private final PermissionApi permissionApi;
+
+    // 设备表名
+    private static final String DEVICE_TABLE = "rq_iot_device";
+    // 设备责任人表名
+    private static final String PERSON_TABLE = "rq_iot_device_person";
+    // 设备ID字段
+    private static final String DEVICE_ID_COLUMN = "id";
+    // 责任人ID字段
+    private static final String PERSON_ID_COLUMN = "person_id";
+
+    @Override
+    public Set<String> getTableNames() {
+        // 只对设备表生效
+        return Collections.singleton(DEVICE_TABLE);
+    }
+
+    @Override
+    public Expression getExpression(String tableName, Alias tableAlias) {
+        // 只处理设备表
+        if (!DEVICE_TABLE.equalsIgnoreCase(tableName)) {
+            return null;
+        }
+
+        // 获取当前登录用户
+        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
+        if (loginUser == null) {
+            return null;
+        }
+
+        // 检查用户是否拥有全部数据权限
+        if (hasAllDataPermission(loginUser)) {
+            return null; // 拥有全部权限时不添加条件
+        }
+
+        try {
+            // 使用字符串解析方式
+            return buildExpressionWithStringParsing(tableAlias, loginUser.getId());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 方法1:使用字符串解析构建表达式(兼容性最好)
+     */
+    private Expression buildExpressionWithStringParsing(Alias tableAlias, Long userId) throws Exception {
+        // 构建设备ID列名(带表别名)
+        String deviceColumn = (tableAlias != null ? tableAlias.getName() + "." : "") + DEVICE_ID_COLUMN;
+
+        // 构建子查询SQL
+        String subQuery = String.format(
+                "(SELECT device_id FROM %s WHERE %s = %d)",
+                PERSON_TABLE, PERSON_ID_COLUMN, userId
+        );
+
+        // 构建完整的IN条件表达式
+        String inExpression = String.format("%s IN %s", deviceColumn, subQuery);
+
+        // 解析为Expression对象
+        return CCJSqlParserUtil.parseCondExpression(inExpression);
+    }
+
+    /**
+     * 检查用户是否拥有全部数据权限
+     */
+    private boolean hasAllDataPermission(LoginUser loginUser) {
+        // 1. 尝试从上下文中获取部门数据权限
+        DeptDataPermissionRespDTO deptPermission = loginUser.getContext(
+                CONTEXT_KEY, DeptDataPermissionRespDTO.class);
+
+        // 2. 如果存在且标记为全部权限,返回 true
+        if (deptPermission != null && deptPermission.getAll()) {
+            return true;
+        }
+
+        // 3. 非管理员用户默认没有全部权限
+        if (!loginUser.getUserType().equals(UserTypeEnum.ADMIN.getValue())) {
+            return false;
+        }
+
+        // 4. 重新计算权限(如果上下文没有缓存)
+        deptPermission = permissionApi.getDeptDataPermission(loginUser.getId());
+        if (deptPermission == null) {
+            return false;
+        }
+
+        // 5. 缓存计算结果
+        loginUser.setContext(CONTEXT_KEY, deptPermission);
+
+        return deptPermission.getAll();
+    }
+
+}

+ 12 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/config/PmsDataPermissionConfiguration.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.pms.config;
 
 import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
+import cn.iocoder.yudao.framework.datapermission.core.rule.device.DevicePersonDataPermissionRule;
 import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.IotInfoDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.IotTreeDO;
@@ -16,6 +17,7 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.iotsapstock.IotSapStockDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.maintain.IotMaintainDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
 import cn.iocoder.yudao.module.supplier.dal.dataobject.product.SupplierDO;
+import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import org.springframework.context.annotation.Bean;
@@ -38,6 +40,9 @@ public class PmsDataPermissionConfiguration {
             rule.addDeptColumn(SupplierDO.class, "dept_id");
             rule.addDeptColumn(IotTreeDO.class,"dept_id");
             rule.addDeptColumn(IotDeviceDO.class,"dept_id");
+            // 添加设备表的用户字段 设备责任人数据权限
+            rule.addUserColumn(IotDeviceDO.class, "creator");
+
             rule.addDeptColumn(IotFailureReportDO.class,"dept_id");
             rule.addDeptColumn(IotInfoDO.class, "dept_id");
             rule.addDeptColumn(IotMaintainDO.class,"dept_id");
@@ -51,12 +56,17 @@ public class PmsDataPermissionConfiguration {
             rule.addDeptColumn(IotMainWorkOrderDO.class, "dept_id");
             rule.addDeptColumn(IotMaintenancePlanDO.class, "dept_id");
             rule.addDeptColumn(IotSapStockDO.class, "dept_id");
+
             // user
-//            rule.addUserColumn(SupplierDO.class);
             rule.addUserColumn(AdminUserDO.class, "id");
-//            rule.addUserColumn(SupplierDO.class, "creator");
 
         };
     }
 
+    // 设备责任人数据权限规则
+    @Bean
+    public DevicePersonDataPermissionRule devicePersonDataPermissionRule(PermissionApi permissionApi) {
+        return new DevicePersonDataPermissionRule(permissionApi);
+    }
+
 }