package cn.iocoder.yudao.module.system.controller.admin.agent;
|
|
import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
|
import cn.iocoder.yudao.module.system.framework.agent.AgentPrincipal;
|
import cn.iocoder.yudao.module.system.framework.agent.SystemAgentBridgeGuard;
|
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
|
import jakarta.annotation.Resource;
|
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import java.nio.charset.StandardCharsets;
|
import java.security.MessageDigest;
|
import java.security.NoSuchAlgorithmException;
|
import java.util.ArrayList;
|
import java.util.Comparator;
|
import java.util.HexFormat;
|
import java.util.List;
|
import java.util.Set;
|
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
/** 为智能体规划返回经过服务端裁剪的菜单、按钮、字段和数据范围能力。 */
|
@RestController
|
@RequestMapping("/agent/bridge")
|
public class SystemAgentCapabilityController {
|
|
private static final List<CapabilityDefinition> CATALOG = List.of(
|
new CapabilityDefinition("mdm.item.import", "mdm.item", "import", "mdm:item:import",
|
Set.of("code", "name", "specification", "categoryCode", "unitMeasureCode")),
|
new CapabilityDefinition("srm.supplier.create", "srm.supplier", "create", "srm:supplier:create",
|
Set.of("code", "name", "shortName", "type", "companyNature", "registeredCapital",
|
"businessLicenseNo", "taxNo", "legalPerson", "address", "website", "contactName",
|
"contactMobile", "contactEmail", "bankName", "bankAccount", "status", "remark")),
|
new CapabilityDefinition("mes.bom.create", "mes.bom", "create", "mes:md-item:create",
|
Set.of("parentCode", "componentCode", "quantity", "status", "remark")),
|
new CapabilityDefinition("mes.qc-template.prepare", "mes.qc-template", "prepare",
|
"mes:qc-template:create", Set.of("code", "name", "types", "indicatorCode",
|
"standardValue", "thresholdMax", "thresholdMin", "unitCode", "itemCode", "remark")),
|
new CapabilityDefinition("mes.mps.prepare", "mes.mps", "prepare", "mes:pro-mps:create",
|
Set.of("productCode", "quantity", "unitCode", "requestDate", "saleOrderNo", "remark")),
|
new CapabilityDefinition("mes.route.prepare", "mes.route", "prepare", "mes:pro-route:create",
|
Set.of("routeCode", "routeName", "itemCode", "processCode", "sort", "yieldRate",
|
"keyFlag", "remark"))
|
);
|
|
@Resource
|
private SystemAgentBridgeGuard bridgeGuard;
|
@Resource
|
private SecurityFrameworkService securityFrameworkService;
|
@Resource
|
private PermissionService permissionService;
|
|
@GetMapping("/capabilities")
|
public CommonResult<CapabilityCatalogResp> capabilities(
|
@RequestHeader(value = "X-Agent-Service-Token", required = false) String serviceToken) {
|
AgentPrincipal principal = bridgeGuard.requireAuthenticated(serviceToken);
|
DeptDataPermissionRespDTO dataScope = permissionService.getDeptDataPermission(principal.userId());
|
List<CapabilityResp> capabilities = new ArrayList<>();
|
for (CapabilityDefinition definition : CATALOG) {
|
if (securityFrameworkService.hasPermission(definition.permission())) {
|
capabilities.add(new CapabilityResp(definition.tool(), definition.module(), definition.operation(),
|
definition.fields().stream().sorted().toList(), scopeSummary(dataScope), true));
|
}
|
}
|
String policyRevision = digest(policyMaterial(principal.userId(), capabilities, dataScope));
|
String authorizationScope = "scope:" + digest(principal.userId() + ":" + policyRevision).substring(0, 32);
|
return success(new CapabilityCatalogResp(policyRevision, authorizationScope,
|
scopeSummary(dataScope), capabilities));
|
}
|
|
private static String scopeSummary(DeptDataPermissionRespDTO scope) {
|
if (Boolean.TRUE.equals(scope.getAll())) {
|
return "全部授权数据";
|
}
|
int departments = scope.getDeptIds() == null ? 0 : scope.getDeptIds().size();
|
if (Boolean.TRUE.equals(scope.getSelf()) && departments > 0) {
|
return "本人及授权部门数据";
|
}
|
if (Boolean.TRUE.equals(scope.getSelf())) {
|
return "仅本人数据";
|
}
|
return departments > 0 ? "授权部门数据" : "无部门数据范围";
|
}
|
|
private static String policyMaterial(Long userId, List<CapabilityResp> capabilities,
|
DeptDataPermissionRespDTO scope) {
|
List<Long> deptIds = scope.getDeptIds() == null ? List.of()
|
: scope.getDeptIds().stream().sorted(Comparator.naturalOrder()).toList();
|
return userId + "|" + Boolean.TRUE.equals(scope.getAll()) + "|" + Boolean.TRUE.equals(scope.getSelf())
|
+ "|" + deptIds + "|" + capabilities.stream().map(CapabilityResp::tool).sorted().toList();
|
}
|
|
private static String digest(String value) {
|
try {
|
return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256")
|
.digest(value.getBytes(StandardCharsets.UTF_8)));
|
} catch (NoSuchAlgorithmException ex) {
|
throw new IllegalStateException("JVM 缺少 SHA-256", ex);
|
}
|
}
|
|
private record CapabilityDefinition(String tool, String module, String operation, String permission,
|
Set<String> fields) {
|
}
|
|
public record CapabilityResp(String tool, String module, String operation, List<String> allowedFields,
|
String scopeSummary, boolean canExecute) {
|
}
|
|
public record CapabilityCatalogResp(String policyRevision, String authorizationScope, String scopeSummary,
|
List<CapabilityResp> capabilities) {
|
}
|
}
|