求助:如何成功生成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
相关产品推荐
相关产品推荐

