How to properly sign a GET request to Amazon's ItemLookup using client-side JavaScript only?

无人久伴 提交于 2019-11-29 07:38:51

I hacked around with your code and I got it working.

function sha256(stringToSign, secretKey) {
  var hex = CryptoJS.HmacSHA256(stringToSign, secretKey);
  return hex.toString(CryptoJS.enc.Base64);
} 

function timestamp() {
    var date = new Date();
    var y = date.getUTCFullYear().toString();
    var m = (date.getUTCMonth() + 1).toString();
    var d = date.getUTCDate().toString();
    var h = date.getUTCHours().toString();
    var min = date.getUTCMinutes().toString();
    var s = date.getUTCSeconds().toString();

    if(m.length < 2) { m = "0" + m; }
    if(d.length < 2) { d = "0" + d; }
    if(h.length < 2) { h = "0" + h; }
    if(min.length < 2) { min = "0" + min; }
    if(s.length < 2) { s = "0" + s}

    var date = y + "-" + m + "-" + d;
    var time = h + ":" + min + ":" + s;
    return date + "T" + time + "Z";
}

function getAmazonItemInfo(barcode) {
    var PrivateKey = "";
    var PublicKey = "";
    var AssociateTag = "";

    var parameters = [];
    parameters.push("AWSAccessKeyId=" + PublicKey);
    parameters.push("ItemId=" + barcode);
    parameters.push("Operation=ItemLookup");
    parameters.push("Service=AWSECommerceService");
    parameters.push("Timestamp=" + encodeURIComponent(timestamp()));
    parameters.push("Version=2011-08-01");
parameters.push("AssociateTag=" + AssociateTag);

    parameters.sort();
    var paramString = parameters.join('&');

    var signingKey = "GET\n" + "webservices.amazon.com\n" + "/onca/xml\n" + paramString

    var signature = sha256(signingKey,PrivateKey);
        signature = encodeURIComponent(signature);

    var amazonUrl =  "http://webservices.amazon.com/onca/xml?" + paramString + "&Signature=" + signature;
    console.log(amazonUrl);
}

The Header of the Javascript I used for some reference.

<script src="hmac-sha256.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"></script>
<script src="amazon.js"></script>

You will need to modify parts of it because I changed some parameters around and don't reference your "app" object.

For what I did to fix it (from what I can recall).

  1. The parameters have to be alphabetical. I placed them in an array and then sort them. I follow this up by a join with the ampersand.

  2. I modified the sha256 function to return the base64 of the RAW sha256. Before it was returning the hexbits in lowercase, which isn't correct.

  3. I was going to add a base64 before encoding, but the sha256 now handles all of the signing.

  4. The date format was incorrect. It was returning a epoch timestamp instead of a string timestamp. I hacked together a simple timestamp option.

    This code requires you to include the Base64 Library for CryptoJS also.

Use this Node.js library for AWS. It even includes an example specifically for the Product Advertising API.

Building on David's great answer, I made some tweaks. The solution below uses moment.js and crytpo-js, and can be used to search for items by keyword. I used the amazon scratch-pad to help build the target call. A couple of things I noticed:

  • The scratch-pad needs to use the same location as your associates account, ".com" ".co.uk", etc.
  • The end point you call to needs to be the same country as your associates account.
  • The time-stamp you use needs to match the local time in the country your associates account is registered.

const getAmazonItemInfo = (keywords) => {

  let date = moment().startOf().add(-9, 'hours').format("YYYY-MM-DDThh:mm:ss.000") + 'Z'
  let SecretKey = "GENERATED_IN_AFFILATES_ACCOUNT";
  let AccessKey = "GENERATED_IN_AFFILATES_ACCOUNT";
  let AssociateTag = "FOUND_IN_AFFILATES_ACCOUNT";
  let parameters = [];
  let url = 'webservices.amazon.co.uk' // UK account
  //let url = 'webservices.amazon.com'// US account

  parameters.push("AWSAccessKeyId=" + AccessKey);
  parameters.push("Keywords=" + keywords);
  parameters.push("Operation=ItemSearch");
  parameters.push("SearchIndex=All");
  parameters.push("ResponseGroup=" + encodeURIComponent('Images,ItemAttributes,Offers'));
  parameters.push("Service=AWSECommerceService");
  parameters.push("Timestamp=" + encodeURIComponent(date));
  parameters.push("AssociateTag=" + AssociateTag);
  parameters.sort();

  let paramString = parameters.join('&');
  let string_to_sign = "GET\n" + url + "\n" + "/onca/xml\n" + paramString

  let signature = CryptoJS.HmacSHA256(string_to_sign, SecretKey);
  signature = CryptoJS.enc.Base64.stringify(signature);

  let amazonUrl = "http://" + url + "/onca/xml?" + paramString + "&Signature=" + signature;
  return amazonUrl;
}

let keywords = 'iphone'
console.log(getAmazonItemInfo(keywords))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!