Magento 2 REST API OAuth签名无效:Postman正常Node-Red(Node.js)报错求助
Magento 2 OAuth签名不匹配问题
我尝试通过OAuth认证调用Magento 2 REST API,该调用在Postman中可正常执行,但在Node-Red(基于Node.js)中调用时返回错误:"签名无效,请验证后重试"。
我将签名生成脚本的参数调整为与Postman一致后,生成的OAuth签名仍和Postman的不匹配,相关信息如下:
我的签名生成脚本
//Variables required from the function calling this flow var p_http_method = "GET"; var p_url = "https://watchguard24.co.za/rest/V1/modules/"; //Static variables for Magento authorization const p_oauth_version = "1.0"; const p_signature_method = "HMAC-SHA256"; const p_nonce = "17TTbZZM0fi" //encodeURIComponent(uuid.v4()); //"35WpXRWuoQp" //uuid.v4(); const p_consumer_key = "wypklfmtf6m53b0rfclxikr2xibopftu"; const p_access_token = "umnmupjtpidzuzz47vuo5s2ianxmq7cf"; const p_consumer_secret = encodeURIComponent("fw17d1k3i70zldcy7xvuvtjjykrzw286"); const p_token_secret = encodeURIComponent("lroq3mg3vteogfisez7hu2zwbu7fmq2x"); const p_timestamp = 1668081726 //Math.floor(Date.now() / 1000); //Combining OAuth parameters const parameters = { oauth_consumer_key: p_consumer_key, oauth_nonce: p_nonce, oauth_signature_method: p_signature_method, oauth_timestamp: p_timestamp, oauth_version: p_oauth_version, oauth_token: p_access_token } //Ordering and encoding the variables let ordered = {}; Object.keys(parameters).sort().forEach(function (key) { ordered[key] = parameters[key]; }); let encodedParameters = ''; for (var k in ordered) { const encodedValue = encodeURIComponent(ordered[k]); const encodedKey = encodeURIComponent(k); if (encodedParameters === '') { encodedParameters += encodeURIComponent(`${encodedKey}=${encodedValue}`) } else { encodedParameters += encodeURIComponent(`&${encodedKey}=${encodedValue}`); } } //Base signature string const encodedUrl = encodeURIComponent(p_url); encodedParameters = encodeURIComponent(encodedParameters); const signature_base_string = encodeURIComponent(`${p_http_method}&${encodedUrl}&${encodedParameters}`) //Create the oauth signature const signing_key = `${p_consumer_secret}&${p_token_secret}` const oauth_signature = crypto.createHmac("sha256", signing_key).update(signature_base_string).digest('base64'); //Encode oauth signature const encoded_oauth_signature = encodeURIComponent(oauth_signature); msg.headers = { "Authorization": 'OAuth oauth_consumer_key=' + p_consumer_key + ',oauth_token=' + p_access_token + ',oauth_signature_method=' + p_signature_method + ',oauth_timestamp=' + p_timestamp + ',oauth_nonce=' + p_nonce + ',oauth_signature=' + encoded_oauth_signature + ',oauth_version=' + p_oauth_version } return msg;
Postman生成的Authorization头
OAuth oauth_consumer_key="wypklfmtf6m53b0rfclxikr2xibopftu", oauth_token="d07jwep9s79srvy3dmjltlfafnpl9d1d", oauth_signature_method="HMAC-SHA256", oauth_timestamp="1668081726", oauth_nonce="17TTbZZM0fi", oauth_version="1.0", oauth_signature="yktg8XIKp%2Fsjk2Wzr4Qk7Mxs6B7kY%2Fjx3040UvwHuY8%3D"
Node-Red生成的Authorization头
OAuth oauth_consumer_key=wypklfmtf6m53b0rfclxikr2xibopftu, oauth_token=d07jwep9s79srvy3dmjltlfafnpl9d1d, oauth_signature_method=HMAC-SHA256, oauth_timestamp=1668081726, oauth_nonce=17TTbZZM0fi, oauth_version=1.0, oauth_signature=8GPa253AV9I%2FIGB9N2s2Urbg7Km%2FUcjhzM%2BeRjuEag4%3D
我已参考Magento 2官方OAuth认证文档及相关Node.js OAuth签名生成教程,但问题仍未解决,需要修正脚本使生成的OAuth签名与Postman一致,以成功调用API。
修正后的脚本及问题说明
你的脚本存在3个关键错误,导致签名不匹配:
- 签名基字符串重复编码:按照OAuth 1.0a规范,只需要分别编码HTTP方法、URL、参数串后用
&拼接,不需要再对整个拼接结果编码。 - 参数串构建逻辑错误:原脚本对每个
key=value片段单独编码,会导致=和&被二次编码,正确做法是先编码key和value,拼接成key=value后用&连接所有项,最后对整个参数串做一次编码。 - Authorization头缺少引号:Postman生成的头中每个参数值都用双引号包裹,原脚本未添加,这会导致认证校验失败。
修正后的脚本:
//Variables required from the function calling this flow var p_http_method = "GET"; var p_url = "https://watchguard24.co.za/rest/V1/modules/"; //Static variables for Magento authorization const p_oauth_version = "1.0"; const p_signature_method = "HMAC-SHA256"; const p_nonce = "17TTbZZM0fi"; const p_consumer_key = "wypklfmtf6m53b0rfclxikr2xibopftu"; const p_access_token = "d07jwep9s79srvy3dmjltlfafnpl9d1d"; // 与Postman使用的token保持一致 const p_consumer_secret = "fw17d1k3i70zldcy7xvuvtjjykrzw286"; // 不要提前编码,签名时再处理 const p_token_secret = "lroq3mg3vteogfisez7hu2zwbu7fmq2x"; const p_timestamp = 1668081726; //Combining OAuth parameters const parameters = { oauth_consumer_key: p_consumer_key, oauth_nonce: p_nonce, oauth_signature_method: p_signature_method, oauth_timestamp: p_timestamp, oauth_version: p_oauth_version, oauth_token: p_access_token } // 1. 按字典序排序参数并生成编码后的键值对 const sortedKeys = Object.keys(parameters).sort(); let paramPairs = []; for (const key of sortedKeys) { const encodedKey = encodeURIComponent(key); const encodedValue = encodeURIComponent(parameters[key]); paramPairs.push(`${encodedKey}=${encodedValue}`); } // 2. 拼接参数串并编码 const encodedParameters = encodeURIComponent(paramPairs.join('&')); // 3. 编码HTTP方法(需大写)和URL const encodedMethod = encodeURIComponent(p_http_method.toUpperCase()); const encodedUrl = encodeURIComponent(p_url); // 4. 构建签名基字符串 const signature_base_string = `${encodedMethod}&${encodedUrl}&${encodedParameters}`; // 生成签名密钥:编码consumer secret和token secret后用&连接 const signing_key = `${encodeURIComponent(p_consumer_secret)}&${encodeURIComponent(p_token_secret)}`; // 生成HMAC-SHA256签名并转base64 const oauth_signature = crypto.createHmac("sha256", signing_key) .update(signature_base_string) .digest('base64'); // 编码签名 const encoded_oauth_signature = encodeURIComponent(oauth_signature); // 构建带双引号的Authorization头 msg.headers = { "Authorization": `OAuth oauth_consumer_key="${p_consumer_key}"` + `,oauth_token="${p_access_token}"` + `,oauth_signature_method="${p_signature_method}"` + `,oauth_timestamp="${p_timestamp}"` + `,oauth_nonce="${p_nonce}"` + `,oauth_signature="${encoded_oauth_signature}"` + `,oauth_version="${p_oauth_version}"` }; return msg;
额外注意点
- 确保
p_access_token与Postman中使用的完全一致(原脚本中的token和Postman里的不匹配) - 签名基字符串中的HTTP方法必须大写
- 不要提前编码consumer secret和token secret,在生成signing key时再进行编码
内容的提问来源于stack exchange,提问作者Renier Duvenhage
相关产品推荐
相关产品推荐

