云
6 小时以前 95ae0c83d2aa58d86b4039e3f7f16ee93afb8f00
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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) {
    }
}