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