我试图在这个指南之后创建一个向亚马逊销售合作伙伴API的请求。
第一部分:创建访问已经被这里处理过了。
订单API的文档可以找到这里。
我正在尝试调用GET /orders/v0/orders
操作。
连接到API
此操作的唯一强制性参数是基于文档的MarketplaceIds
。
为了得到订单,我们需要在我们的请求上签字。到目前为止,我的代码如下:
function GetOrders(){
var access_token = AccessToken();
//Time variables
var currentDate = new Date();
var isoDate = currentDate.toISOString();
var yearMonthDay= Utilities.formatDate(currentDate, 'GTM-5', 'yyyyMMdd');
//API variables
var end_point = 'https://sellingpartnerapi-eu.amazon.com';
//Credential variables
var aws_region = "eu-west-1";
var service = "execute-api";
var termination_string = "aws4_request";
//CanonicalRequest = httpRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload));
//CanonicalRequest components:
var httpRequestMethod = 'GET';
var canonicalURI = '/orders/v0/orders';
var canonicalQueryString = '?marketplaceId=A1PA6795UKMFR9';
var canonicalheaders = 'host:' + canonicalURI + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate;
var signedheaders = 'host;user-agent;x-amz-access-token;x-amz-date';
var requestPayloadHashed = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, "");//NEW
requestPayloadHashed = requestPayloadHashed.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");//NEW
//Building the canonical request
var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + canonicalQueryString + '\n' + canonicalheaders + '\n' + signedheaders + '\n' + requestPayloadHashed;//UPDATED
var canonical_signature = Utilities.computeHmacSha256Signature(canonical_string, ACCESS_KEY);
var canonical_request = canonical_string + '\n' + canonical_signature;
canonical_request = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, canonical_request);//NEW
//CredentialScope = Date + AWS region + Service + Termination string;
//StringToSign = Algorithm + \n + RequestDateTime + \n + CredentialScope + \n + HashedCanonicalRequest;
var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;
var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoDate + '\n' + credential_scope + '\n' + canonical_request;
var kSecret = ACCESS_KEY;
var kDate = Utilities.computeHmacSha256Signature(yearMonthDay, "AWS4" + kSecret);
var kRegion = Utilities.computeHmacSha256Signature(Utilities.newBlob(aws_region).getBytes(), kDate);
var kService = Utilities.computeHmacSha256Signature(Utilities.newBlob(service).getBytes(), kRegion);
var kSigning = Utilities.computeHmacSha256Signature(Utilities.newBlob(termination_string).getBytes(), kService);
kSigning = kSigning.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
Logger.log('kSigning: ' + kSigning);
var signature = Utilities.computeHmacSha256Signature(kSigning, string_to_sign);
signature = signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
var options = {
'method': 'GET',
'payload': {
'end_point': end_point,
'path': canonicalURI,
'query_string': canonicalQueryString
//Path parameter not needed
},
'headers': {
//'host': end_point,
'x-amz-access-token': access_token,
'x-amz-date': isoDate,
'user-agent': 'GAS Script 1.0 (Javascript)',
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
},
}
var getOrders = UrlFetchApp.fetch(end_point, options);
Logger.log(getOrders);
}
问题
在运行脚本时,我会得到以下错误:
Exception: Request failed for https://sellingpartnerapi-eu.amazon.com returned code 403. Truncated server response: {
{
"errors": [
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'POST
/
host:sellingpartnerapi-eu.amazon.com
user-agent:Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)
x-amz-access-token:Atza|IwEBSomeAccessToken
x-amz-date:2021-03-10T02:44:01.727Z
host;user-agent;x-amz-access-token;x-amz-date
cf22942946358a7530d8b72df6333e859644aaebb08a1cd825a6af65a8561111'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210310T024401Z
20210310/eu-west-1/execute-api/aws4_request
c4c1dcea7026765f52c5265296f9e1cb91b6618928debbc04a393bac89ce8493'
",
"code": "InvalidSignature"
}
]
}
问题
我对什么是“有效载荷”有很大的疑问。
对于守则的这一部分:
var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + canonicalQueryString + '\n' + canonicalheaders + '\n' + signedheaders + '\n' + requestPayloadHashed;
我们必须合并有效负载请求requestPayloadHashed
的散列版本。
它还提到:
如果有效负载为空,则使用空字符串作为哈希函数的输入。
现在,我只创建了一个空白值的变量。
var requestPayloadHashed = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, "");//NEW
requestPayloadHashed = requestPayloadHashed.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");//NEW
但我不确定我是不是在说什么重要的事。
更新#1
在应用Tanaike推荐之后,我得到了以下信息:
{
"errors": [
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'GET
/orders/v0/orders
marketplaceId=A1PA6795UKMFR9
host:sellingpartnerapi-eu.amazon.com
user-agent:Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)
x-amz-access-token:Atza|IwEBISomeAccessToken
x-amz-date:2021-03-10T03:00:14.411Z
host;user-agent;x-amz-access-token;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210310T030014Z
20210310/eu-west-1/execute-api/aws4_request
f1bbc99190ca5a9e9e068ad6a0b2ef6a7aed4a1232095ef8f3d77ad62d0e66ac'
",
"code": "InvalidSignature"
}
]
}
更新2这个网站帮助我们对这些连接进行一些测试:
https://mws.amazonservices.de/scratchpad/index.html
通过使用它,我相信我已经验证了Access Key ID
和Secret Key
,然而,它要求的是一个对我来说是新的、在API文档中也没有提到的SellerId。
我想知道它会去哪里。
更新#3
我实现了大多数Tanaike建议,并尝试将发送到API的内容与我收到的错误消息相一致:
这是脚本的最后一个版本:
function GetOrders(){
var access_token = AccessToken();
//Time variables
var currentDate = new Date();
var isoDate = currentDate.toISOString();
var isoString = isoDate.replace(/-/g, "").replace(/:/g, "").replace(/(\.\d{3})/, "");
var yearMonthDay= Utilities.formatDate(currentDate, 'GTM-5', 'yyyyMMdd');
Logger.log('isoDate: ' + isoDate)
//API variables
var end_point = 'https://sellingpartnerapi-eu.amazon.com';
//Credential variables
var aws_region = "eu-west-1";
var service = "execute-api";
var termination_string = "aws4_request";
//CanonicalRequest = httpRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload));
//CanonicalRequest components:
var httpRequestMethod = 'GET';
var canonicalURI = '/orders/v0/orders';
var canonicalQueryString = '?marketplaceId=A1PA6795UKMFR9';
var canonicalheaders = 'host:' + "sellingpartnerapi-eu.amazon.com" + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate;
var signedheaders = 'host;x-amz-access-token;x-amz-date';//;user-agent
var requestPayloadHashed = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, "");//NEW
requestPayloadHashed = requestPayloadHashed.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");//NEW
//Building the canonical request
var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + "marketplaceId=A1PA6795UKMFR9" + '\n' + canonicalheaders + '\n\n' + signedheaders + '\n' + requestPayloadHashed;//UPDATED
Logger.log('canonical_string: ' + canonical_string)
var canonical_signature = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, canonical_string);
canonical_request = canonical_signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
Logger.log("canonical_request: " + canonical_request)
//CredentialScope = Date + AWS region + Service + Termination string;
//StringToSign = Algorithm + \n + RequestDateTime + \n + CredentialScope + \n + HashedCanonicalRequest;
var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;
var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoString + '\n' + credential_scope + '\n' + canonical_request;
Logger.log("string_to_sign: " + string_to_sign);
var kSecret = ACCESS_KEY;
var kDate = Utilities.computeHmacSha256Signature(yearMonthDay, "AWS4" + kSecret);
var kRegion = Utilities.computeHmacSha256Signature(toBytes(aws_region), kDate);
var kService = Utilities.computeHmacSha256Signature(toBytes(service), kRegion);
var kSigning = Utilities.computeHmacSha256Signature(toBytes(termination_string), kService);
Logger.log('kSigning: ' + kSigning);
var signature = hex(Utilities.computeHmacSha256Signature(toBytes(string_to_sign), kSigning));
Logger.log('signature: ' + signature)
var options = {
'method': 'GET',
'headers': {
//'host': end_point,
'x-amz-access-token': access_token,
'x-amz-date': isoDate,
//'user-agent': 'Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; +https://script.google.com; id: UAEmdDd-KyWEWcR137UzUzWb1fu3rUgNviHA)',
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
},
'muteHttpExceptions': true
}
var getOrders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
Logger.log(getOrders);
}
我现在得到了一个与我的访问完全相关的错误:
{
"errors": [
{
"message": "Access to requested resource is denied.",
"code": "Unauthorized",
"details": ""
}
]
}
然而,这可能是因为当我注册应用程序(guide 这里)时,我使用的是IAM用户,而不是IAM角色。
指南上写着:
很重要。在注册您的应用程序时,您提供的IAM ARN必须是从第3步开始附加IAM策略的IAM实体。创建一个IAM策略。在这个工作流中,IAM实体是步骤4中的IAM角色。创建一个IAM角色。如果您使用IAM用户注册应用程序,请确保IAM策略已附加到该应用程序。否则,您对销售伙伴API的调用将失败。我们建议使用IAM角色注册应用程序,如此工作流所示,以帮助您更好地控制对AWS资源的访问。
所以我要去解决这个问题,看看我是否得到了我需要的授权。
发布于 2021-03-10 02:57:46
修改要点:
UrlFetchApp
的情况下,当使用payload
时,即使method
是GET
,也会请求它作为POST请求。这似乎是当前的规范。user-agent
不能更改为UrlFetchApp
。作为一个先决条件,当您的授权值是请求端点的正确值时,您的脚本可以按下面的反映点进行修改。
我认为您的错误消息可能是由于"GET“和"POST”方法之间的差异造成的。首先,请测试以下修改。发生错误时,请出示。
修改脚本:
发自:
var options = {
'method': 'GET',
'payload': {
'end_point': end_point,
'path': canonicalURI,
'query_string': canonicalQueryString
//Path parameter not needed
},
'headers': {
//'host': end_point,
'x-amz-access-token': access_token,
'x-amz-date': isoDate,
'user-agent': 'GAS Script 1.0 (Javascript)',
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
},
}
var getOrders = UrlFetchApp.fetch(end_point, options);
至:
var options = {
'method': 'GET',
'headers': {
'x-amz-access-token': access_token,
'x-amz-date': isoDate,
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
},
}
var getOrders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
参考资料:
添加:
在用签名版本4签署AWS请求中,我修改了您的脚本。当我看到您的脚本时,我注意到字节数组包含在字符串值中。我认为这也可能是你提出问题的原因之一。所以我修改了你的剧本。你能确认一下吗?当我看到正式文档时,我确认当字节数组用于Utilities.computeHmacSha256Signature
时,将字符串值转换为字节数组与示例相同,而不是将字节数组转换为字符串值。
function sample() {
const hex = bytes => bytes.map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
const digestToHex = data => hex(Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, data));
const toBytes = data => Utilities.newBlob(data).getBytes();
const ACCESS_ID = "MyAccessKey";
const ACCESS_KEY = "MyAccessSecret";
var access_token = "access_token"; // AccessToken();
//Time variables
var currentDate = new Date();
var isoDate = currentDate.toISOString();
var yearMonthDay= Utilities.formatDate(currentDate, 'GTM-5', 'yyyyMMdd');
//API variables
var end_point = 'https://sellingpartnerapi-eu.amazon.com';
//Credential variables
var aws_region = "eu-west-1";
var service = "execute-api";
var termination_string = "aws4_request";
// 1. Create string to sign.
var httpRequestMethod = 'GET';
var canonicalURI = '/orders/v0/orders';
var canonicalQueryString = '?marketplaceId=A1PA6795UKMFR9';
var canonicalheaders = 'host:' + canonicalURI + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate;
var signedheaders = 'host;user-agent;x-amz-access-token;x-amz-date';
const canonicalRequest = [httpRequestMethod,canonicalURI,canonicalQueryString,canonicalheaders + "\n",signedheaders,digestToHex("")].join("\n");
const canonical_request = digestToHex(canonicalRequest);
var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;
var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoDate + '\n' + credential_scope + '\n' + canonical_request;
// 2. Create derived signing key.
var kSecret = ACCESS_KEY;
var kDate = Utilities.computeHmacSha256Signature(yearMonthDay, "AWS4" + kSecret);
var kRegion = Utilities.computeHmacSha256Signature(toBytes(aws_region), kDate);
var kService = Utilities.computeHmacSha256Signature(toBytes(service), kRegion);
var kSigning = Utilities.computeHmacSha256Signature(toBytes(termination_string), kService);
// 3. Create signature.
const signature = hex(Utilities.computeHmacSha256Signature(toBytes(string_to_sign), kSigning));
// 4. Request.
var options = {
'method': 'GET',
'headers': {
'x-amz-access-token': access_token,
'x-amz-date': isoDate,
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
},
}
var getOrders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
Logger.log(getOrders);
}
注意:
const canonicalRequest = [httpRequestMethod,canonicalURI,canonicalQueryString,canonicalheaders + "\n",signedheaders,digestToHex("")].join("\n");
,当上面的脚本发生错误时,请测试const canonicalRequest = [httpRequestMethod,canonicalURI,canonicalQueryString,canonicalheaders + "\n",""].join("\n");
。参考资料:
https://stackoverflow.com/questions/66557069
复制相似问题