You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何成功生成Walmart.io的WM_SEC.AUTH_SIGNATURE签名

Walmart.io API签名密钥生成失败问题排查与修复

核心问题分析

你得到Signature: null的直接原因是代码中静默吞掉了所有异常,导致无法定位具体错误。此外代码还存在内部类使用、私钥处理等潜在问题,以下是具体修复方案:


1. 取消异常静默捕获

原代码中try-catch块没有任何异常处理逻辑,把所有错误都隐藏了。必须添加异常打印,才能看到问题所在:

try {
    data = generator.generateSignature(key, array[1]);
} catch(Exception e) {
    // 打印异常信息,定位问题
    e.printStackTrace();
}

2. 修复内部类实例化问题

ServiceKeyRep是非静态内部类,在静态方法generateSignature中直接创建会抛出IllegalStateException,需要将其改为静态内部类:

static class ServiceKeyRep extends KeyRep  {
    private static final long serialVersionUID = -7213340660431987616L;
    public ServiceKeyRep(Type type, String algorithm, String format, byte[] encoded) {
        super(type, algorithm, format, encoded);
    }
    protected Object readResolve() throws ObjectStreamException {
        return super.readResolve();
    }
}

3. 确认私钥格式正确性

Walmart要求使用PKCS#8格式的Base64编码私钥:

  • 如果你的私钥是PKCS#1格式(开头为-----BEGIN RSA PRIVATE KEY-----),需要先转换为PKCS#8格式,可通过OpenSSL命令转换:
    openssl pkcs8 -topk8 -inform PEM -outform PEM -in your_private_key.pem -out pkcs8_key.pem -nocrypt
    
  • 转换后去掉首尾的-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----,只保留中间的Base64字符串作为代码中的key值。

4. 修正后的完整代码

package com.walmart.platform.common;

import java.io.ObjectStreamException;
import java.security.KeyRep;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.codec.binary.Base64;

public class SignatureGenerator {

    public static void main(String[] args) {
        SignatureGenerator generator = new SignatureGenerator();

        String consumerId = "36e010ef-0026-4713-9365-231323116afd";
        String priviateKeyVersion = "2";
        // 替换为你正确的PKCS#8格式Base64私钥
        String key = "jUiewb1+QbHl7ls+LoBO...O4j2NVjC2If4Z/r5FrykDVcO+nxb8G95X+zl";

        long intimestamp = System.currentTimeMillis();

        System.out.println("consumerId: " + consumerId);
        System.out.println("intimestamp: " + intimestamp);

        Map<String, String> map = new HashMap<>();
        map.put("WM_CONSUMER.ID", consumerId);
        map.put("WM_CONSUMER.INTIMESTAMP", Long.toString(intimestamp));
        map.put("WM_SEC.KEY_VERSION", priviateKeyVersion);

        String[] array = canonicalize(map);

        String data = null;

        try {
            data = generator.generateSignature(key, array[1]);
        } catch(Exception e) {
            // 打印异常信息,方便排查
            e.printStackTrace();
        }
        System.out.println("Signature: " + data);
    }

    public String generateSignature(String key, String stringToSign) throws Exception {
        Signature signatureInstance = Signature.getInstance("SHA256WithRSA");

        ServiceKeyRep keyRep = new ServiceKeyRep(KeyRep.Type.PRIVATE, "RSA", "PKCS#8", Base64.decodeBase64(key));

        PrivateKey resolvedPrivateKey = (PrivateKey) keyRep.readResolve();

        signatureInstance.initSign(resolvedPrivateKey);

        byte[] bytesToSign = stringToSign.getBytes("UTF-8");
        signatureInstance.update(bytesToSign);
        byte[] signatureBytes = signatureInstance.sign();

        String signatureString = Base64.encodeBase64String(signatureBytes);

        return signatureString;
    }

    protected static String[] canonicalize(Map<String, String> headersToSign) {
        StringBuffer canonicalizedStrBuffer = new StringBuffer();
        StringBuffer parameterNamesBuffer = new StringBuffer();
        Set<String> keySet = headersToSign.keySet();

        // Create sorted key set to enforce order on the key names
        SortedSet<String> sortedKeySet = new TreeSet<>(keySet);
        for (String key : sortedKeySet) {
            Object val = headersToSign.get(key);
            parameterNamesBuffer.append(key.trim()).append(";");
            canonicalizedStrBuffer.append(val.toString().trim()).append("\n");
        }
        return new String[] {parameterNamesBuffer.toString(), canonicalizedStrBuffer.toString()};
    }

    // 修改为静态内部类
    static class ServiceKeyRep extends KeyRep  {
        private static final long serialVersionUID = -7213340660431987616L;
        public ServiceKeyRep(Type type, String algorithm, String format, byte[] encoded) {
            super(type, algorithm, format, encoded);
        }
        protected Object readResolve() throws ObjectStreamException {
            return super.readResolve();
        }
    }
}

内容的提问来源于stack exchange,提问作者Alex 111

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 02:55:29