自动化立体仓库 - WMS系统
#
zjj
2025-09-02 598c9d63f68a8c92b264328c88c1cb4ef25af044
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
118
package com.zy.kingdee.utils;
 
 
import com.smecloud.apigw.util.SHAUtil;
import lombok.extern.slf4j.Slf4j;
 
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
 
@Slf4j
public class KingDeeUtils {
    public static String generateSignature(String method,
                                           String path,
                                           Map<String, String> params,
                                           Map<String, String> headers,
                                           String appSecret) throws Exception {
        // 1. 处理请求方法(转大写)
        String processedMethod = method.toUpperCase();
 
        // 2. 处理路径(URL编码+大写)
        String processedPath = encodePath(path);
 
        // 3. 处理请求参数(双重URL编码+ASCII排序+大写)
        String processedParams = processParams(params);
 
        // 4. 处理请求头(提取特定参数)
        String nonce = headers.getOrDefault("x-api-nonce", "");
        String timestamp = headers.getOrDefault("x-api-timestamp", "");
 
        // 5. 构建签名原文
        String signSource = buildSignSource(processedMethod, processedPath, processedParams, nonce, timestamp);
 
        log.info("签名原文:\n"+signSource);
        // 6. 计算HMAC-SHA256签名
        return hmacSha256(appSecret, signSource);
    }
 
    private static String encodePath(String path) {
        try {
            // 只对路径部分进行URL编码(不包含协议/域名)
            String[] parts = path.split("://", 2);
            String toEncode = parts.length > 1 ? parts[1].substring(parts[1].indexOf('/')) : path;
            return URLEncoder.encode(toEncode, StandardCharsets.UTF_8.name()).toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("Path encoding failed", e);
        }
    }
 
    private static String processParams(Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return "";
        }
 
        // 按参数名ASCII升序排序
        TreeMap<String, String> sortedParams = new TreeMap<>(params);
        StringBuilder sb = new StringBuilder();
 
        try {
            for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
                if (sb.length() > 0) {
                    sb.append('&');
                }
                // 双重URL编码(每次编码后转大写)
                String key = doubleUrlEncode(entry.getKey());
                String value = doubleUrlEncode(entry.getValue());
                sb.append(key).append('=').append(value);
            }
        } catch (Exception e) {
            throw new RuntimeException("Parameter encoding failed", e);
        }
        return sb.toString();
    }
 
    private static String doubleUrlEncode(String s) throws Exception {
        if (s == null) return "";
        String firstEncode = URLEncoder.encode(s, StandardCharsets.UTF_8.name());
        return URLEncoder.encode(firstEncode, StandardCharsets.UTF_8.name());
    }
 
    private static String buildSignSource(String method,
                                          String path,
                                          String params,
                                          String nonce,
                                          String timestamp) {
        return method + "\n" +
                path + "\n" +
                params + "\n" +
                "x-api-nonce:" + nonce + "\n" +
                "x-api-timestamp:" + timestamp + "\n";  // 注意结尾的换行符
    }
 
    private static String hmacSha256(String secret, String message) throws Exception {
        Mac sha256 = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        sha256.init(secretKey);
        byte[] hash = sha256.doFinal(message.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hash);
    }
 
    private static String hmacSha256_16(String secret, String message) throws Exception {
        String appSignature = SHAUtil.SHA256HMAC(message, secret);
        appSignature = Base64.getEncoder().encodeToString(appSignature.getBytes());
        return appSignature;
    }
 
    // 测试示例
    public static void main(String[] args) throws Exception {
        // 示例数据
 
 
        System.out.println("X-Api-Signature: " + hmacSha256_16("abc123","abc"));
    }
}