NetSuite SOAP API签名生成与文档不符问题排查
NetSuite令牌认证签名不一致问题排查
我正在基于令牌认证流程构建Node.js版NetSuite集成。按照文档示例编写单元测试时,基础字符串(base string)和密钥(key)的生成结果均与文档一致,但使用HMAC SHA256算法生成的签名却与文档给出的示例不符。改用文档示例使用的Java语言实现后,得到的签名结果仍与Node.js版本一致,而与文档示例不同。目前集成还遇到“无效凭证”错误,需要确认是代码问题、文档存在错误,或是遗漏了某些步骤。
通过的单元测试
it("Generates a base string", () => { const baseString = shared.exportsForTest.genBaseString(__testConfig, __docNonce, __docTimestamp); expect(baseString).toEqual(__docBaseString); }); it("Generates a key", () => { const key = shared.exportsForTest.genKey(__testConfig); expect(key).toEqual(__docKey); });
失败的单元测试
it("Generates a signature", () => { const baseString = shared.exportsForTest.genBaseString(__testConfig, __docNonce, __docTimestamp); const key = shared.exportsForTest.genKey(__testConfig); const signature = shared.exportsForTest.genSignature({ baseString, key }); expect(signature).toEqual(__docSignature); });
核心生成函数定义
__genBaseString(基础字符串生成)
function __genBaseString(config: INetSuiteConfig, nonce: string, timestamp: DateTime) { return _.join([ config.accountId, config.consumerKey, config.tokenId, nonce, timestamp.toUnixInteger() // Timestamp as epoch time. ], '&'); }
__genKey(密钥生成)
function __genKey(config: INetSuiteConfig) { return _.join([ config.consumerSecret, config.tokenSecret ], '&'); }
__genSignature(签名生成)
function __genSignature({ baseString, key }: { baseString: string; key: string; }) { const keyAsBytes = Buffer.from(key, 'utf-8'); const baseStringAsBytes = Buffer.from(baseString, 'utf-8'); const hash = crypto.createHmac('sha256', keyAsBytes) .update(baseStringAsBytes) .digest(); return hash.toString('base64'); }
程序生成的签名为 FCghIZqXNetuZY8ILWOFH0ucdfzQOmAuL+q+kF21zPs=,文档给出的签名为 fzGxUBu6SZvGqv5hk8P4ou2DPthSxXtJ4zJIeCBQK5A=
文档提供的测试值
const __testConfig: shared.INetSuiteConfig = { accountId: '1234567', applicationId: '', consumerKey: '71cc02b731f05895561ef0862d71553a3ac99498a947c3b7beaf4a1e4a29f7c4', consumerSecret: '7278da58caf07f5c336301a601203d10a58e948efa280f0618e25fcee1ef2abd', tokenId: '89e08d9767c5ac85b374415725567d05b54ecf0960ad2470894a52f741020d82', tokenSecret: '060cd9ab3ffbbe1e3d3918e90165ffd37ab12acc76b4691046e2d29c7d7674c2' }; const __docBaseString = '1234567&71cc02b731f05895561ef0862d71553a3ac99498a947c3b7beaf4a1e4a29f7c4&89e08d9767c5ac85b374415725567d05b54ecf0960ad2470894a52f741020d82&6obMKq0tmY8ylVOdEkA1&1439829974'; const __docKey = '7278da58caf07f5c336301a601203d10a58e948efa280f0618e25fcee1ef2abd&060cd9ab3ffbbe1e3d3918e90165ffd37ab12acc76b4691046e2d29c7d7674c2'; const __docNonce = '6obMKq0tmY8ylVOdEkA1'; const __docSignature = 'fzGxUBu6SZvGqv5hk8P4ou2DPthSxXtJ4zJIeCBQK5A='; const __docTimestamp = DateTime.fromSeconds(1439829974);
Java对比实现代码
import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; class SignatureTestProgram { public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException { SignatureTestProgram hello = new SignatureTestProgram(); String signature = hello.computeShaHash( hello.getBaseString(), hello.getKey(), "HmacSHA256" ); System.out.println(signature); } public String getBaseString() { return "1234567" + // account "&" + "71cc02b731f05895561ef0862d71553a3ac99498a947c3b7beaf4a1e4a29f7c4" + // consumer key "&" + "89e08d9767c5ac85b374415725567d05b54ecf0960ad2470894a52f741020d82" + // token "&" + "6obMKq0tmY8ylVOdEkA1" + // nonce "&" + "1439829974"; // timestamp } public String getKey() { return "7278da58caf07f5c336301a601203d10a58e948efa280f0618e25fcee1ef2abd" + // consumer secret "&" + "060cd9ab3ffbbe1e3d3918e90165ffd37ab12acc76b4691046e2d29c7d7674c2"; // token secret } public String computeShaHash(String baseString, String key, String algorithm) throws NoSuchAlgorithmException, InvalidKeyException { byte[] bytes = key.getBytes(); SecretKeySpec mySigningKey = new SecretKeySpec(bytes, algorithm); Mac messageAuthenticationCode = Mac.getInstance(algorithm); messageAuthenticationCode.init(mySigningKey); byte[] hash = messageAuthenticationCode.doFinal(baseString.getBytes()); return new String(java.util.Base64.getEncoder().encode(hash)); } }
内容的提问来源于stack exchange,提问作者Andrew D
相关产品推荐
相关产品推荐

