使用NetSuite SuiteScript 2.0生成Cybersource HTTP签名遇认证失败
SuiteScript 2.0 生成Cybersource HTTP签名示例
以下是适配NetSuite SuiteScript 2.0的Cybersource退款API签名生成代码,解决认证失败的核心是严格遵循Cybersource的签名规范构造待签名字符串:
核心代码实现
/** * @NApiVersion 2.x * @NScriptType Restlet * @NModuleScope SameAccount */ define(['N/crypto', 'N/https', 'N/runtime'], function(crypto, https, runtime) { function post(context) { // 从脚本参数读取Cybersource配置(避免硬编码) const apiKeyId = runtime.getCurrentScript().getParameter({name: 'custscript_cybersource_api_key_id'}); const secretKey = runtime.getCurrentScript().getParameter({name: 'custscript_cybersource_secret_key'}); const merchantId = runtime.getCurrentScript().getParameter({name: 'custscript_cybersource_merchant_id'}); const apiUrl = 'https://apitest.cybersource.com/pts/v2/refunds'; // 测试环境地址,生产环境替换 // 构造退款请求体 const requestBody = JSON.stringify({ "clientReferenceInformation": { "code": "REFUND_ORDER_001" }, "paymentInformation": { "id": "REPLACE_WITH_PAYMENT_ID" // 替换为实际支付ID }, "orderInformation": { "amountDetails": { "totalAmount": "10.00", "currency": "USD" } } }); // 生成签名必备参数 const httpMethod = 'POST'; const requestPath = '/pts/v2/refunds'; const timestamp = Math.floor(Date.now() / 1000).toString(); // 秒级时间戳 const nonce = crypto.generateRandomString({ length: 32, charset: crypto.Charset.HEXADECIMAL }); // 计算请求体SHA256摘要(Base64编码) const digest = crypto.createHash({ algorithm: crypto.HashAlg.SHA256 }).update({input: requestBody, inputEncoding: crypto.Encoding.UTF_8}).digest({outputEncoding: crypto.Encoding.BASE_64}); // 构造待签名字符串(严格按指定顺序拼接,换行分隔) const signatureString = [ httpMethod, requestPath, timestamp, nonce, digest ].join('\n'); // 生成HMAC-SHA256签名 const hmac = crypto.createHmac({ algorithm: crypto.HashAlg.SHA256, key: secretKey }); hmac.update({input: signatureString, inputEncoding: crypto.Encoding.UTF_8}); const signature = hmac.digest({outputEncoding: crypto.Encoding.BASE_64}); // 构造符合要求的请求头 const headers = { 'Content-Type': 'application/json', 'v-c-merchant-id': merchantId, 'Signature': `keyid="${apiKeyId}",algorithm="HmacSHA256",headers="host date request-target digest v-c-merchant-id",signature="${signature}"`, 'Date': new Date().toUTCString(), // RFC 1123格式UTC时间 'Host': 'apitest.cybersource.com', // 测试环境主机,生产环境替换 'Digest': `SHA-256=${digest}` }; // 发送退款请求 const response = https.post({ url: apiUrl, body: requestBody, headers: headers }); return { statusCode: response.code, responseBody: response.body }; } return { post: post }; });
避免认证失败的关键细节
- 签名字符串顺序:必须严格按照
请求方法、请求路径、时间戳、随机数、请求体摘要的顺序拼接,不能调整顺序 - 时间同步:签名用的秒级时间戳要和
Date头的UTC时间保持误差在5分钟内,否则会被判定为无效请求 - 路径准确性:请求路径必须和API文档完全一致,不能多/少斜杠或额外参数
- 摘要匹配:
Digest头的内容要和签名字符串里的摘要完全一致,编码格式必须是Base64 - 密钥安全:API密钥、商户ID必须通过脚本参数或自定义记录存储,禁止硬编码在代码中
内容的提问来源于stack exchange,提问作者Ba.Lal
相关产品推荐
相关产品推荐

