[英]dropbox api usage in nodejs “Bad oauth_signature for oauth_signature_method”
[英]oauth_signature invalid error while using Magento Rest API with GET filters
當我使用它的 GET 過濾器時,我很難從 Magento REST API 獲取訂單http://localhost/magento/api/rest/orders/?filter[1][attribute]=entity_id&filter[1][gt] =70&頁=1&限制=100
它給出了一個“錯誤”:[{“代碼”:401,“消息”:“oauth_problem = signature_invalid”}]
當我嘗試使用 REST 客戶端(如 Postman)訪問相同的 API 端點時,我得到了所需的結果 JSON。
我懷疑過濾器查詢中的方括號可能會導致生成 Oauth 簽名時出現問題。 所有沒有 GET 過濾器的端點都工作正常。 我正在使用 Request 節點模塊發出帶有 oauth 標頭的 GET 請求。
是否有任何修復來避免簽名無效錯誤?
問題出在我用來生成OAuth簽名的Request節點模塊中。它沒有考慮URL中的方括號。 我修改了模塊中包含方括號的代碼。 更改OAuth簽名生成方法為我修復了它
因為我花了一點時間才弄清楚如何做到這一點,我想我會傳遞我學到的東西。 我的目標是向Magento的REST API發出單一請求,以返回具有特定訂單狀態的訂單。 在看到最后一行之前,查看GET過濾器文檔頁面並沒有什么用處。 以下是我提出的有效的請求:
http://magentohost.com/api/rest/orders?filter[1][attribute]=status&filter[1][in][1]=pending&filter[1][in][2]=processing上述請求將獲得您是狀態為“待定”或“處理”的所有訂單的列表。
參考: http : //magentoforce.com/2014/08/magento-rest-api-multiple-in-get-filters/
對於任何想要回答這個問題的人來說,這對我有用:
const axios = require('axios');
const crypto = require('crypto');
exports.handler = async (event) => {
let base_uri = 'https://YOUR_URL.com'; (ANYTHING UP TO THE /PATH)
const consumer_key = '';
const token_key = '';
const consumer_secret = '';
const token_secret = '';
==> CHANGE THE QUERY PARAMS TO WHATEVER YOU HAVE <==
const queryParameters = {
'searchCriteria[filterGroups][0][filters][0][field]': 'sku',
'searchCriteria[filterGroups][0][filters][0][condition_type]': 'eq',
'searchCriteria[filterGroups][0][filters][0][value]': 'aaaaaaaaa',
};
const timestamp = Math.floor(Date.now() / 1000);
const nonce = await generateNonce();
==> ADD IN YOUR PATH, IT WILL BE APPENDED TO THE BASE URL <==
const path = 'products';
base_uri = `${base_uri}/${path}`;
const reqsign256 = hmacsign256('GET', base_uri, { ...queryParameters, oauth_consumer_key: consumer_key, oauth_nonce: nonce, oauth_signature_method: 'HMAC-SHA256', oauth_timestamp: timestamp, oauth_token: token_key, oauth_version: '1.0' }, consumer_secret, token_secret);
const config = {
method: 'get',
url: base_uri,
headers: {
Authorization: `OAuth oauth_consumer_key="${consumer_key}",oauth_token="${token_key}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="${timestamp}",oauth_nonce="${nonce}",oauth_version="1.0",oauth_signature="${reqsign256}"`
},
params: queryParameters,
};
let response = {};
return await axios(config)
.then(async (response) => {
response = {
statusCode: 200,
body: JSON.stringify(response.data),
};
return response;
})
.catch((error) => {
response = {
statusCode: 200,
body: JSON.stringify(error.message),
};
return response;
});
};
/**
*
* @returns A random string of 11 characters
*/
function generateNonce() {
let nonce = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 11; i++) {
nonce += possible.charAt(Math.floor(Math.random() * possible.length));
}
return nonce;
}
/**
*
* @param key
* @param body
* @param algorithm
* @description This is generating the signature using the imported crypto package.
* @returns The generated signature;
*/
function sha(key, body, algorithm) {
return crypto.createHmac(algorithm, key).update(body).digest('base64');
}
/**
*
* @param str
* @description The rfc3986 function takes a string as input and returns its encoded representation as per the rules specified in RFC 3986
* for URI (Uniform Resource Identifier) component encoding. It does this by first using encodeURIComponent to encode the string,
* which replaces certain characters with their percent-encoded representations. It then replaces characters such as !, *, (, ), and '
* with their respective percent-encoded representations, which are specified in RFC 3986 as being reserved characters that must be percent-encoded.
* @returns returns the encoded str value
*/
function rfc3986(str) {
return encodeURIComponent(str).replace(/!/g, '%21').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/'/g, '%27');
}
/**
*
* @param obj
* @description The map function takes an object as input and returns an array of its key-value pairs.
* It does this by iterating through the properties of the object using a for...in loop, and for each property, it checks its value.
* If the value is an array, it pushes an array with the property key and each value of the array into the result array.
* If the value is an object, it pushes an array with a string representation of the property key concatenated with the property name in square brackets
* and the property value into the result array.
* If the value is neither an array nor an object, it pushes an array with the property key and value into the result array.
* Finally, it returns the result array.
* @returns arr
*/
function map(obj) {
let key,
val,
arr = [];
for (key in obj) {
val = obj[key];
if (Array.isArray(val)) for (let i = 0; i < val.length; i++) arr.push([key, val[i]]);
else if (typeof val === 'object') for (let prop in val) arr.push([key + '[' + prop + ']', val[prop]]);
else arr.push([key, val]);
}
return arr;
}
/**
*
* @param a
* @param b
* @description Used to sort the oauth paramters into ascending order -- this is required for oauth1 to work.
* @returns the comparison result
*/
function compare(a, b) {
return a > b ? 1 : a < b ? -1 : 0;
}
/**
*
* @param httpMethod
* @param base_uri
* @param params
* @description
* 1. First, the name and value of each parameter are encoded
* 2. The parameters are sorted by name, using ascending byte value ordering. If two or more parameters share the same name, they are sorted by their value.
* 3. The name of each parameter is concatenated to its corresponding value using an "=" character (ASCII code 61) as a separator, even if the value is empty.
* for example in this case it is assigning oauth_nonce = 'foo' or oauth_signature_method = 'HMAC-SHA256' etc
* 4. The sorted name/value pairs are concatenated together into single string by using an "&" character (ASCII code 38) as separator.
* The final output will be something like this:
* GET&https%3A%2F%2Fstaging2.ospreylondon.com%2Frest%2FV1%2Fproducts&oauth_consumer_key%3Dxxx%26oauth_nonce%3xxxoauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3Dxxx%26oauth_token%3xxx%26oauth_version%3D1.0%26 ==> There will also be any url paramaters added at the end.
* @returns base url
*/
function generateBase(httpMethod, base_uri, params) {
let normalized = map(params)
// step 1
.map(function (p) {
return [rfc3986(p[0]), rfc3986(p[1] || '')];
})
// step 2
.sort(function (a, b) {
return compare(a[0], b[0]) || compare(a[1], b[1]);
})
//step 3
.map(function (p) {
return p.join('=');
})
//step 4
.join('&');
let base = [rfc3986(httpMethod ? httpMethod.toUpperCase() : 'GET'), rfc3986(base_uri), rfc3986(normalized)].join('&');
return base;
}
/**
*
* @param httpMethod
* @param base_uri
* @param params
* @param consumer_secret
* @param token_secret
* @description This takes the paramaters passed in, creates a base uri, creates a key (consumer secret and token secret with & between them)
* @returns this then returns the result of the sha method ==> this is the signature used in the request.
*/
function hmacsign256(httpMethod, base_uri, params, consumer_secret, token_secret) {
let base = generateBase(httpMethod, base_uri, params);
let key = [consumer_secret || '', token_secret || ''].map(rfc3986).join('&');
return sha(key, base, 'sha256');
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.