From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionDecisionService.java |  148 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 148 insertions(+), 0 deletions(-)

diff --git a/jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionDecisionService.java b/jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionDecisionService.java
new file mode 100644
index 0000000..3c24cca
--- /dev/null
+++ b/jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionDecisionService.java
@@ -0,0 +1,148 @@
+package jnpf.dmsService;
+
+import jnpf.base.UserInfo;
+import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity;
+import jnpf.dmsEntity.permission.enums.DmsPermissionAction;
+import jnpf.dmsEntity.permission.form.PermissionDecisionForm;
+import jnpf.dmsEntity.permission.model.DmsResourcePath;
+import jnpf.dmsEntity.permission.model.DmsSubjectSet;
+import jnpf.dmsEntity.permission.vo.DmsPermissionDecisionVO;
+import jnpf.dmsMapper.DmsFilePermissionMapper;
+import jnpf.dmsIntegration.audit.DmsAuditAdapter;
+import jnpf.dmsPermission.DmsAccessExclusionResolver;
+import jnpf.dmsPermission.DmsCurrentIdentity;
+import jnpf.dmsPermission.DmsPermissionError;
+import jnpf.dmsPermission.DmsPermissionException;
+import jnpf.dmsPermission.DmsPermissionGroupMembershipResolver;
+import jnpf.dmsPermission.DmsPermissionMatcher;
+import jnpf.dmsPermission.DmsPermissionProperties;
+import jnpf.dmsPermission.DmsResourceResolver;
+import jnpf.dmsPermission.DmsSubjectResolver;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+public class DmsPermissionDecisionService {
+    private final DmsCurrentIdentity currentIdentity;
+    private final DmsSubjectResolver subjectResolver;
+    private final DmsResourceResolver resourceResolver;
+    private final DmsFilePermissionMapper permissionMapper;
+    private final DmsPermissionGroupMembershipResolver groupMembershipResolver;
+    private final DmsPermissionMatcher matcher;
+    private final DmsPermissionProperties properties;
+    private final DmsAuditAdapter auditAdapter;
+    private final DmsAccessExclusionResolver exclusionResolver;
+
+    @Transactional(readOnly = true)
+    public DmsPermissionDecisionVO evaluate(PermissionDecisionForm request) {
+        return evaluate(Collections.singletonList(request)).get(0);
+    }
+
+    @Transactional(readOnly = true)
+    public List<DmsPermissionDecisionVO> evaluate(List<PermissionDecisionForm> requests) {
+        if (requests == null || requests.isEmpty() || requests.size() > properties.getMaxDecisionBatchSize()) {
+            throw DmsPermissionException.of(DmsPermissionError.INVALID_REQUEST,
+                    "瑁佸喅鎵归噺澶у皬蹇呴』鍦� 1 鍒� " + properties.getMaxDecisionBatchSize() + " 涔嬮棿");
+        }
+        UserInfo user = currentIdentity.requireUser();
+        String tenantId = currentIdentity.tenantId(user);
+        Map<UUID, DmsResourcePath> paths = resourceResolver.resolveAll(tenantId, requests);
+        List<DmsResourcePath> readPaths = requests.stream()
+                .filter(request -> request.getActionCode() == DmsPermissionAction.READ)
+                .map(request -> paths.get(request.getResourceId()))
+                .collect(Collectors.toList());
+        DmsAccessExclusionResolver.Snapshot exclusions = exclusionResolver.resolve(
+                tenantId, user.getUserId().trim(), readPaths);
+
+        List<PermissionDecisionForm> eligibleRequests = requests.stream()
+                .filter(request -> !isReadExcluded(request, paths.get(request.getResourceId()), exclusions))
+                .collect(Collectors.toList());
+
+        Map<String, List<DmsFilePermissionEntity>> candidatesByAction = new java.util.HashMap<>();
+        Set<String> permissionGroupIds = new LinkedHashSet<>();
+        DmsSubjectSet subjects = null;
+        if (!eligibleRequests.isEmpty()) {
+            subjects = subjectResolver.resolve(user);
+            LinkedHashSet<String> actionCodes = new LinkedHashSet<>();
+            LinkedHashSet<UUID> resourceIds = new LinkedHashSet<>();
+            for (PermissionDecisionForm request : eligibleRequests) {
+                actionCodes.add(request.getActionCode().name());
+                resourceIds.addAll(resourceResolver.candidateResourceIds(paths.get(request.getResourceId())));
+            }
+            List<DmsFilePermissionEntity> candidates = permissionMapper.selectCandidates(tenantId,
+                    new ArrayList<>(actionCodes), new ArrayList<>(resourceIds));
+            for (DmsFilePermissionEntity candidate : candidates) {
+                candidatesByAction.computeIfAbsent(candidate.getActionCode(), key -> new ArrayList<>())
+                        .add(candidate);
+                if ("GROUP".equals(candidate.getPrincipalType())) {
+                    permissionGroupIds.add(candidate.getPrincipalId());
+                }
+            }
+            groupMembershipResolver.resolve(permissionGroupIds, subjects);
+        }
+
+        List<DmsPermissionDecisionVO> result = new ArrayList<>();
+        for (PermissionDecisionForm request : requests) {
+            DmsPermissionDecisionVO decision = denied(request);
+            DmsResourcePath path = paths.get(request.getResourceId());
+            if (isReadExcluded(request, path, exclusions)) {
+                decision.setReasonCode("USER_READ_EXCLUDED");
+            } else {
+                for (DmsFilePermissionEntity candidate : candidatesByAction.getOrDefault(
+                        request.getActionCode().name(), Collections.<DmsFilePermissionEntity>emptyList())) {
+                    if (matcher.matches(candidate, path, subjects)) {
+                        decision.setAllowed(true);
+                        decision.setReasonCode("ALLOWED");
+                        decision.setMatchedPermissionId(candidate.getId());
+                        if (candidate.getMaxUseCount() != null) {
+                            decision.setRemainingUseCount(candidate.getMaxUseCount() - candidate.getUsedCount());
+                        }
+                        break;
+                    }
+                }
+            }
+            auditAdapter.permissionDecision(decision.isAllowed(), request.getActionCode().name(),
+                    request.getResourceId().toString(), "{\"reasonCode\":\"" + decision.getReasonCode() + "\"}");
+            result.add(decision);
+        }
+        return result;
+    }
+
+    private boolean isReadExcluded(PermissionDecisionForm request, DmsResourcePath path,
+                                   DmsAccessExclusionResolver.Snapshot exclusions) {
+        return request.getActionCode() == DmsPermissionAction.READ && exclusions.excludes(path);
+    }
+
+    public void requireAllowed(jnpf.dmsEntity.permission.enums.DmsResourceType type, UUID id,
+                               jnpf.dmsEntity.permission.enums.DmsPermissionAction action) {
+        PermissionDecisionForm request = new PermissionDecisionForm();
+        request.setResourceType(type);
+        request.setResourceId(id);
+        request.setActionCode(action);
+        if (!evaluate(request).isAllowed()) {
+            throw DmsPermissionException.of(DmsPermissionError.PERMISSION_DENIED,
+                    "褰撳墠鐢ㄦ埛娌℃湁鎵�闇�鐨� " + action.name() + " 鏉冮檺");
+        }
+    }
+
+    private DmsPermissionDecisionVO denied(PermissionDecisionForm request) {
+        DmsPermissionDecisionVO result = new DmsPermissionDecisionVO();
+        result.setResourceId(request.getResourceId());
+        result.setResourceType(request.getResourceType().name());
+        result.setActionCode(request.getActionCode().name());
+        result.setAllowed(false);
+        result.setReasonCode("NO_MATCHING_PERMISSION");
+        return result;
+    }
+}

--
Gitblit v1.8.0