package cn.iocoder.yudao.module.system.controller.admin.agent; import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.system.framework.agent.AgentBridgeException; import cn.iocoder.yudao.module.system.framework.agent.AgentDelegationToken; import cn.iocoder.yudao.module.system.framework.agent.SystemAgentBridgeGuard; import cn.iocoder.yudao.module.system.framework.agent.SystemAgentDelegationService; import cn.iocoder.yudao.module.system.service.storage.SystemAgentImportBridgeService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Size; import lombok.Data; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.Map; import java.util.LinkedHashSet; import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; /** 浏览器以当前登录身份为异步 Worker 签发短期、可撤销、限定范围的委托票据。 */ @RestController @RequestMapping("/agent/bridge/delegations") public class SystemAgentDelegationController { private static final String IMPORT_PERMISSIONS_EXPR = "@ss.hasAnyPermissions('mdm:item:import','srm:supplier:create','mes:md-item:create'," + "'mes:qc-template:create','mes:pro-mps:create','mes:pro-route:create')"; private static final Set ALLOWED_OPERATIONS = Set.of( "material_import.prepare", "material_import.read", "material_import.review", "material_import.preflight", "material_import.commit", "material_import.read_receipt", "conversation.create", "conversation.read", "conversation.message", "conversation.action", "conversation.report", "attachment.read", "import.modules.read", "import.preflight", "import.commit", "import.receipt.read"); private static final Map MODULE_PERMISSIONS = Map.of( "mdm.item", SystemAgentBridgeGuard.PERMISSION_ITEM_IMPORT, "srm.supplier", "srm:supplier:create", "mes.bom", "mes:md-item:create", "mes.qc-template", "mes:qc-template:create", "mes.mps", "mes:pro-mps:create", "mes.route", "mes:pro-route:create"); @Resource private SystemAgentBridgeGuard bridgeGuard; @Resource private SystemAgentDelegationService delegationService; @Resource private SystemAgentImportBridgeService bridgeService; @Resource private PermissionCommonApi permissionApi; @PostMapping @PreAuthorize(IMPORT_PERMISSIONS_EXPR) public CommonResult issue( @RequestHeader(value = "X-Agent-Service-Token", required = false) String serviceToken, @Valid @RequestBody IssueRequest request) { bridgeGuard.verifyServiceToken(serviceToken); if (!ALLOWED_OPERATIONS.containsAll(request.getOperations())) { throw new AgentBridgeException(HttpStatus.BAD_REQUEST, "DELEGATION_OPERATION_INVALID", "委托包含不支持的操作"); } Set attachmentIds = request.normalizedAttachmentIds(); for (Long attachmentId : attachmentIds) { bridgeService.requireOwnedAttachmentRef(attachmentId); } String permission = resolvePermission(request.getModuleId()); AgentDelegationToken token = delegationService.issue(request.getTaskId(), request.getModuleId(), attachmentIds, request.getOperations(), permission); return success(token); } @DeleteMapping("/{delegationId}") @PreAuthorize(IMPORT_PERMISSIONS_EXPR) public CommonResult revoke( @RequestHeader(value = "X-Agent-Service-Token", required = false) String serviceToken, @PathVariable String delegationId) { bridgeGuard.verifyServiceToken(serviceToken); delegationService.revoke(delegationId, SecurityFrameworkUtils.getLoginUserId()); return success(true); } private String resolvePermission(String moduleId) { if (moduleId != null && !moduleId.isBlank()) { String permission = MODULE_PERMISSIONS.get(moduleId); if (permission == null) { throw new AgentBridgeException(HttpStatus.BAD_REQUEST, "MODULE_NOT_SUPPORTED", "不支持的导入模块"); } return permission; } Long userId = SecurityFrameworkUtils.getLoginUserId(); return SystemAgentBridgeGuard.IMPORT_PERMISSIONS.stream() .filter(permission -> permissionApi.hasAnyPermissions(userId, permission)) .findFirst() .orElseThrow(() -> new AgentBridgeException(HttpStatus.FORBIDDEN, "FORBIDDEN", "当前用户缺少数据导入权限")); } @Data public static class IssueRequest { @NotBlank private String taskId; private String moduleId; private Long attachmentId; @Size(max = 20) private Set attachmentIds; @NotEmpty private Set operations; public Set normalizedAttachmentIds() { Set values = new LinkedHashSet<>(); if (attachmentIds != null) { values.addAll(attachmentIds); } if (attachmentId != null) { values.add(attachmentId); } if (values.stream().anyMatch(id -> id == null || id <= 0) || values.size() > 20) { throw new AgentBridgeException(HttpStatus.BAD_REQUEST, "DELEGATION_SCOPE_INVALID", "委托附件范围无效"); } return values; } } }