Explorar el Código

提交权限开发

chenxiaofei hace 2 meses
padre
commit
e5ec53cc75

+ 152 - 64
sckw-modules/sckw-system/src/main/java/com/sckw/system/service/DataPermissionHelper.java

@@ -4,6 +4,7 @@ import com.sckw.core.utils.CollectionUtils;
 import com.sckw.core.web.context.LoginUserHolder;
 import com.sckw.system.api.model.dto.res.DataPermissionDTO;
 import com.sckw.system.model.KwsRole;
+import com.sckw.system.model.KwsUser;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -39,6 +40,9 @@ public class DataPermissionHelper {
     @Autowired
     private KwsRoleService kwsRoleService;
 
+    @Autowired
+    private KwsUserService kwsUserService;
+
     /**
      * 获取当前登录用户的数据权限过滤条件
      * <p>
@@ -51,49 +55,144 @@ public class DataPermissionHelper {
      * @return 数据权限过滤条件
      */
     public DataPermissionFilter getPermissionFilter() {
-        DataPermissionFilter filter = new DataPermissionFilter();
         Long userId = LoginUserHolder.getUserId();
+        log.info("开始计算数据权限过滤条件, userId={}", userId);
+
+        DataPermissionFilter filter = new DataPermissionFilter();
         filter.setUserId(userId);
 
         // 平台管理员默认可见全部
         if (LoginUserHolder.isManager()) {
             Long roleId = LoginUserHolder.getCurrentRoleId();
+            log.info("当前用户为平台管理员, userId={}, roleId={}", userId, roleId);
             if (Objects.isNull(roleId)) {
+                log.info("平台管理员未指定角色ID,默认拥有全部数据权限, userId={}", userId);
                 filter.setAllVisible(true);
                 return filter;
             }
-            return buildFilterByRole(roleId, userId);
+            DataPermissionFilter result = buildFilterByRole(roleId, userId, false);
+            log.info("平台管理员基于角色构建权限完成, userId={}, roleId={}, allVisible={}, entIdsSize={}",
+                    userId, roleId, result.isAllVisible(),
+                    result.getVisibleEntIds() != null ? result.getVisibleEntIds().size() : 0);
+            return result;
         }
 
         // 客户端用户:获取当前使用的角色
         Long roleId = LoginUserHolder.getCurrentRoleId();
+        log.info("当前用户为客户端用户, userId={}, currentRoleId={}", userId, roleId);
+
         if (Objects.isNull(roleId)) {
             // 无角色,查询用户所有角色取并集
+            log.info("当前用户未指定角色ID,尝试获取用户所有角色并集, userId={}", userId);
             List<KwsRole> roles = kwsRoleService.queryRoleByUserId(userId);
             if (CollectionUtils.isEmpty(roles)) {
+                log.warn("用户无任何角色关联,设置为无数据权限, userId={}", userId);
                 filter.setAllVisible(false);
                 filter.setVisibleEntIds(Collections.emptySet());
                 return filter;
             }
-            return buildFilterByRoles(roles, userId);
+            DataPermissionFilter result = buildFilterByRoles(roles, userId, true);
+            log.info("基于用户多角色并集构建权限完成, userId={}, roleCount={}, allVisible={}, entIdsSize={}",
+                    userId, roles.size(), result.isAllVisible(),
+                    result.getVisibleEntIds() != null ? result.getVisibleEntIds().size() : 0);
+            return result;
         }
 
-        return buildFilterByRole(roleId, userId);
+        DataPermissionFilter result = buildFilterByRole(roleId, userId, true);
+        log.info("基于单角色构建权限完成, userId={}, roleId={}, allVisible={}, entIdsSize={}",
+                userId, roleId, result.isAllVisible(),
+                result.getVisibleEntIds() != null ? result.getVisibleEntIds().size() : 0);
+        return result;
+    }
+
+    /**
+     * 解析受限的企业ID集合
+     * <p>
+     * 确保返回的企业ID在当前用户所属企业或角色所属企业的合法范围内。
+     *
+     * @param role           角色信息
+     * @param userId         用户ID
+     * @param configuredEntIds 配置的企业ID集合
+     * @return 经过校验后的企业ID集合
+     */
+    private Set<Long> resolveScopedEntIds(KwsRole role, Long userId, Set<Long> configuredEntIds) {
+        if (Objects.isNull(role) || Objects.isNull(role.getEntId())) {
+            log.warn("角色信息不完整,无法解析企业权限, userId={}, roleId={}", userId, role != null ? role.getId() : null);
+            return Collections.emptySet();
+        }
+
+        Long userEntId = resolveUserEntId(userId);
+        // 校验用户所属企业与角色所属企业是否一致(防止跨企业越权)
+        if (Objects.nonNull(userEntId) && !Objects.equals(userEntId, role.getEntId())) {
+            log.warn("数据权限企业不匹配,可能存在越权风险, userId={}, userEntId={}, roleId={}, roleEntId={}",
+                    userId, userEntId, role.getId(), role.getEntId());
+            return Collections.emptySet();
+        }
+
+        // 如果未配置具体企业ID,则默认仅允许访问角色所属企业
+        if (CollectionUtils.isEmpty(configuredEntIds)) {
+            log.debug("未配置具体企业权限,默认限制为角色所属企业, userId={}, roleId={}, entId={}",
+                    userId, role.getId(), role.getEntId());
+            return new HashSet<>(Collections.singleton(role.getEntId()));
+        }
+
+        // 保留配置中与角色所属企业一致的ID(通常配置中只包含角色所属企业或其子企业,此处做交集校验)
+        // 注意:retainAll会修改原集合,这里假设configuredEntIds是副本或允许修改
+        configuredEntIds.retainAll(Collections.singleton(role.getEntId()));
+        log.debug("解析受限企业ID完成, userId={}, roleId={}, finalEntIds={}", userId, role.getId(), configuredEntIds);
+        return configuredEntIds;
+    }
+
+    /**
+     * 解析用户所属的企业ID
+     *
+     * @param userId 用户ID
+     * @return 企业ID,若用户不存在则返回null
+     */
+    private Long resolveUserEntId(Long userId) {
+        if (Objects.isNull(userId)) {
+            return null;
+        }
+        KwsUser user = kwsUserService.selectByKey(userId);
+        if (user == null) {
+            log.warn("未找到用户信息, userId={}", userId);
+            return null;
+        }
+        return user.getEntId();
     }
 
     /**
      * 根据单个角色构建过滤条件
+     *
+     * @param roleId          角色ID
+     * @param userId          用户ID
+     * @param restrictToOwnedEnt 是否限制在用户所属企业范围内
+     * @return 数据权限过滤条件
      */
-    private DataPermissionFilter buildFilterByRole(Long roleId, Long userId) {
+    private DataPermissionFilter buildFilterByRole(Long roleId, Long userId, boolean restrictToOwnedEnt) {
+        log.debug("开始构建单角色权限过滤, userId={}, roleId={}, restrictToOwnedEnt={}", userId, roleId, restrictToOwnedEnt);
+
         DataPermissionFilter filter = new DataPermissionFilter();
         filter.setUserId(userId);
 
-        Set<Long> entIds = kwsDataPermissionService.getCachedEntIds(roleId);
+        // 获取角色配置的企业ID列表
+        Set<Long> entIds = new HashSet<>(kwsDataPermissionService.getCachedEntIds(roleId));
+        // 获取是否开启个人数据权限(仅看本人)
         boolean personalFlag = kwsDataPermissionService.getCachedPersonalFlag(roleId);
+        log.debug("读取角色缓存权限, roleId={}, configuredEntIdsSize={}, personalFlag={}",
+                roleId, entIds.size(), personalFlag);
+
+        // 如果需要限制在所属企业范围内,进行二次校验
+        if (restrictToOwnedEnt) {
+            KwsRole role = kwsRoleService.selectByKey(roleId);
+            entIds = resolveScopedEntIds(role, userId, entIds);
+        }
 
         if (CollectionUtils.isEmpty(entIds)) {
-            // 未配置企业数据权限,默认可见全部(兼容旧数据)
-            filter.setAllVisible(true);
+            // 未配置企业数据权限或校验后为空,设置为不可见任何企业数据(除非allVisible为true,但此处显式设为false)
+            log.info("角色无有效企业数据权限,设置为空权限, userId={}, roleId={}", userId, roleId);
+            filter.setAllVisible(false);
+            filter.setVisibleEntIds(Collections.emptySet());
         } else {
             filter.setAllVisible(false);
             filter.setVisibleEntIds(entIds);
@@ -105,8 +204,16 @@ public class DataPermissionHelper {
 
     /**
      * 根据多个角色构建过滤条件(取并集)
+     *
+     * @param roles           角色列表
+     * @param userId          用户ID
+     * @param restrictToOwnedEnt 是否限制在用户所属企业范围内
+     * @return 数据权限过滤条件
      */
-    private DataPermissionFilter buildFilterByRoles(List<KwsRole> roles, Long userId) {
+    private DataPermissionFilter buildFilterByRoles(List<KwsRole> roles, Long userId, boolean restrictToOwnedEnt) {
+        log.debug("开始构建多角色权限过滤(并集), userId={}, roleCount={}, restrictToOwnedEnt={}",
+                userId, roles.size(), restrictToOwnedEnt);
+
         DataPermissionFilter filter = new DataPermissionFilter();
         filter.setUserId(userId);
 
@@ -114,76 +221,41 @@ public class DataPermissionHelper {
         boolean anyPersonalFlag = false;
 
         for (KwsRole role : roles) {
-            Set<Long> entIds = kwsDataPermissionService.getCachedEntIds(role.getId());
+            // 获取当前角色配置的企业ID
+            Set<Long> entIds = new HashSet<>(kwsDataPermissionService.getCachedEntIds(role.getId()));
+
+            // 如果需要限制在所属企业范围内,进行二次校验
+            if (restrictToOwnedEnt) {
+                entIds = resolveScopedEntIds(role, userId, entIds);
+            }
+
+            // 合并企业ID
             if (CollectionUtils.isNotEmpty(entIds)) {
                 allEntIds.addAll(entIds);
             }
+
+            // 只要有一个角色开启了个人数据权限,最终结果即开启
             if (kwsDataPermissionService.getCachedPersonalFlag(role.getId())) {
                 anyPersonalFlag = true;
             }
         }
 
         if (allEntIds.isEmpty()) {
-            filter.setAllVisible(true);
+            log.info("多角色合并后无有效企业数据权限,设置为空权限, userId={}", userId);
+            filter.setAllVisible(false);
+            filter.setVisibleEntIds(Collections.emptySet());
         } else {
             filter.setAllVisible(false);
             filter.setVisibleEntIds(allEntIds);
+            log.debug("多角色权限合并完成, userId={}, totalEntIdsSize={}, anyPersonalFlag={}",
+                    userId, allEntIds.size(), anyPersonalFlag);
         }
 
         filter.setPersonalDataEnabled(anyPersonalFlag);
         return filter;
     }
 
-    /**
-     * 将过滤条件应用到查询参数Map中
-     * <p>
-     * 业务Mapper XML中使用:
-     * <pre>
-     * &lt;if test="dataPermEntIds != null and dataPermEntIds.size() > 0"&gt;
-     *     AND ent_id IN
-     *     &lt;foreach collection="dataPermEntIds" item="item" open="(" close=")" separator=","&gt;
-     *         #{item}
-     *     &lt;/foreach&gt;
-     * &lt;/if&gt;
-     * &lt;if test="dataPermUserId != null"&gt;
-     *     AND salesman_id = #{dataPermUserId}
-     * &lt;/if&gt;
-     * </pre>
-     *
-     * @param params 查询参数Map
-     */
-    public void applyFilter(Map<String, Object> params) {
-        DataPermissionFilter filter = getPermissionFilter();
-
-        if (filter.isAllVisible() && !filter.isPersonalDataEnabled()) {
-            return;
-        }
-
-        if (!filter.isAllVisible() && CollectionUtils.isNotEmpty(filter.getVisibleEntIds())) {
-            params.put("dataPermEntIds", new ArrayList<>(filter.getVisibleEntIds()));
-        }
-
-        if (filter.isPersonalDataEnabled()) {
-            params.put("dataPermUserId", filter.getUserId());
-        }
-    }
-
-    /**
-     * 判断当前用户是否有权查看指定企业的数据
-     *
-     * @param targetEntId 目标企业ID
-     * @return true=有权限
-     */
-    public boolean hasEntPermission(Long targetEntId) {
-        DataPermissionFilter filter = getPermissionFilter();
-        if (filter.isAllVisible()) {
-            return true;
-        }
-        return CollectionUtils.isNotEmpty(filter.getVisibleEntIds())
-                && filter.getVisibleEntIds().contains(targetEntId);
-    }
 
-    // ==================== 跨模块调用支持(Dubbo) ====================
 
     /**
      * 根据显式参数获取数据权限过滤条件(不依赖LoginUserHolder,适用于Feign远程调用)
@@ -194,28 +266,39 @@ public class DataPermissionHelper {
      * @return 数据权限过滤条件
      */
     public DataPermissionFilter getPermissionFilter(Long userId, Long roleId, boolean isManager) {
+        log.info("通过显式参数计算数据权限过滤条件, userId={}, roleId={}, isManager={}", userId, roleId, isManager);
+
         DataPermissionFilter filter = new DataPermissionFilter();
         filter.setUserId(userId);
 
         if (isManager) {
             if (Objects.isNull(roleId)) {
+                log.info("平台管理员未指定角色ID,默认拥有全部数据权限, userId={}", userId);
                 filter.setAllVisible(true);
                 return filter;
             }
-            return buildFilterByRole(roleId, userId);
+            DataPermissionFilter result = buildFilterByRole(roleId, userId, false);
+            log.info("平台管理员基于角色构建权限完成(远程调用), userId={}, roleId={}", userId, roleId);
+            return result;
         }
 
         if (Objects.isNull(roleId)) {
+            log.info("客户端用户未指定角色ID,尝试获取用户所有角色并集(远程调用), userId={}", userId);
             List<KwsRole> roles = kwsRoleService.queryRoleByUserId(userId);
             if (CollectionUtils.isEmpty(roles)) {
+                log.warn("用户无任何角色关联,设置为无数据权限(远程调用), userId={}", userId);
                 filter.setAllVisible(false);
                 filter.setVisibleEntIds(Collections.emptySet());
                 return filter;
             }
-            return buildFilterByRoles(roles, userId);
+            DataPermissionFilter result = buildFilterByRoles(roles, userId, true);
+            log.info("基于用户多角色并集构建权限完成(远程调用), userId={}, roleCount={}", userId, roles.size());
+            return result;
         }
 
-        return buildFilterByRole(roleId, userId);
+        DataPermissionFilter result = buildFilterByRole(roleId, userId, true);
+        log.info("基于单角色构建权限完成(远程调用), userId={}, roleId={}", userId, roleId);
+        return result;
     }
 
     /**
@@ -230,12 +313,17 @@ public class DataPermissionHelper {
      * @return 可序列化的数据权限过滤DTO
      */
     public DataPermissionDTO buildPermissionDTO(Long userId, Long roleId, boolean isManager) {
+        log.info("构建数据权限DTO, userId={}, roleId={}, isManager={}", userId, roleId, isManager);
         DataPermissionFilter filter = getPermissionFilter(userId, roleId, isManager);
         DataPermissionDTO dto = new DataPermissionDTO();
         dto.setUserId(filter.getUserId());
         dto.setAllVisible(filter.isAllVisible());
         dto.setVisibleEntIds(filter.getVisibleEntIds());
         dto.setPersonalDataEnabled(filter.isPersonalDataEnabled());
+        log.info("数据权限DTO构建完成, allVisible={}, entIdsSize={}, personalEnabled={}",
+                dto.isAllVisible(),
+                dto.getVisibleEntIds() != null ? dto.getVisibleEntIds().size() : 0,
+                dto.isPersonalDataEnabled());
         return dto;
     }
 
@@ -254,4 +342,4 @@ public class DataPermissionHelper {
         private boolean personalDataEnabled;
     }
 
-}
+}