2

我与 amazon spapi 进行了集成,但我无法从 api 获得受限令牌。我无法签署请求。我签名的请求与 api 的请求不匹配。这是我的 js 签名代码。该代码制作了一个授权句子,我用 Postman 尝试了这个句子。邮递员的结果在这里。

    {
    "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
/tokens/2021-03-01/restrictedDataToken

host:sandbox.sellingpartnerapi-eu.amazon.com
user-agent:PostmanRuntime/7.28.2
x-amz-access-token:Atza|*****

host;user-agent;x-amz-access-token
2328dd129c329e308cb990d33878a6d5ffd2a8c96e62d13b873dc62d5a7ff20b'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210805T134800Z
20210805/eu-west-1/execute-api/aws4_request
c2f03a5e26f63dfae25fcf4cb1490c88fcbdcb78760d357f9234b5d46ac0f824'
",
     "code": "InvalidSignature"
        }
    ]
}

我的错在哪里?

签名者.html

<html>

<head>
    <style>
        table {
            width: 80%
        }

        input {
            width: 100%;
        }

        textarea {
            width:100%;
            height: 200px;
        }
    </style>
</head>

<body>
    <table>
        <tr>
            <td width="10%">Access Key Id</td>
            <td>
                <input type="text" id="accessKeyId" name="accessKeyId" value="AKIAZIX*******" />
            </td>
        </tr>
        <tr>
            <td>Secret Access Key</td>
            <td>
                <input type="text" id="secretAccessKey" name="secretAccessKey" value="3nwTlA06******" />
            </td>
        </tr>
        <tr>
            <td>Access Token</td>
            <td>
                <input type="text" id="token" name="token" value="" />
            </td>
        </tr>
        <tr>
            <td>Region</td>
            <td>
                <input type="text" id="region" name="region" value="eu-west-1" />
            </td>
        </tr>
        <tr>
            <td>Service</td>
            <td>
                <input type="text" id="service" name="service" value="execute-api" />
            </td>
        </tr>
        <tr>
            <td>Method</td>
            <td>
                <input type="text" id="method" name="method" value="POST" />
            </td>
        </tr>
        <tr>
            <td>Host</td>
            <td>
                <input type="text" id="host" name="host" value="sandbox.sellingpartnerapi-eu.amazon.com" />
            </td>
        </tr>
        <tr>
            <td>URI</td>
            <td>
                <input type="text" id="uri" name="uri" value="/tokens/2021-03-01/restrictedDataToken" />
            </td>
        </tr>
        <tr>
            <td>Query</td>
            <td>
                <input type="text" id="query" name="query" value="" />
            </td>
        </tr>
        <tr>
            <td>Data</td>
            <td>
                <input type="text" id="data" name="data" value='{"restrictedResources":[{"method":"GET","path":"/catalog/2020-12-01/items"}]}' />
            </td>
        </tr>
        <tr>
            <td>Header</td>
            <td><textarea id="header"></textarea></td>
        </tr>
        <tr>
            <td></td>
            <td><button id="send">Send</button></td>
        </tr>
    </table>

    <script src="script/crypto-js.min.js"></script>
    <script src="script/sha256.min.js"></script>
    <script src="script/hmac-sha256.min.js"></script>
    <script src="script/enc-base64.min.js"></script>
    <script src="script/bundle.js"></script>

    <script type="text/javascript">
        document.getElementById('send').onclick = function () {
            var crd = new Credentials(
                document.getElementById('accessKeyId').value,
                document.getElementById('secretAccessKey').value,
                document.getElementById('token').value,
                document.getElementById('region').value,
                document.getElementById('service').value       
            );

            var req = new Requests(
                document.getElementById('method').value,
                document.getElementById('host').value,
                document.getElementById('uri').value,
                document.getElementById('query').value,
                document.getElementById('data').value
                );

            var signer = new Signer(crd,req);

            document.getElementById('header').value = signer.execute();
        }
    </script>
</body>

</html>

bundle.js

class Credentials {
  constructor(accessKeyId, secretAccessKey, token, region, service) {
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.token = token;
    this.region = region;
    this.service = service;
  }
}

class Requests {
  constructor(method, host, uri, query, data) {
    this.method = method;
    this.host = host;
    this.uri = uri;
    this.query = query;
    this.data = data;
  }
}

class Signer {
  private
  date = new Date();
  termStr = "aws4_request";
  algo = "AWS4-HMAC-SHA256";
  signedHeaders = "host;user-agent;x-amz-access-token";
  userAgent = "PostmanRuntime/7.28.2";

  canonicalHeaders = function () {
    var a = new Array(
      "host:" + this.request.host,
      "user-agent:" + this.userAgent,
      "x-amz-access-token:" + this.credentials.token
    );

    return a.join("\n");
  };

  canonicalRequest = function () {
    var result = '';

    var a = new Array(
      this.request.method.toUpperCase(),
      this.request.uri,
      this.queryParameters(this.request.query),
      this.canonicalHeaders() + "\n",
      this.signedHeaders,
      this.hash(this.request.data)
    );

    result = a.join("\n"); 
    console.log("canonicalRequest : \n"+result);

    return result;
  };

  credentialScope = function () {
    var a = new Array(
      this.amzShortDate(),
      this.credentials.region,
      this.credentials.service,
      this.termStr
    );

    return a.join("/");
  };

  requestToSign = function () {
    var result = '';

    var a = new Array(
      this.algo,
      this.amzLongDate(),
      this.credentialScope(),
      this.hash(this.canonicalRequest())
    );

    result = a.join("\n"); 
    console.log("requestToSign : \n"+result);

    return result;
  };

  signature = function () {
    var result = "";

    result = this.hmac(
      "AWS4" + this.credentials.secretAccessKey,
      this.amzShortDate()
    );
    result = this.hmac(result, this.credentials.region);
    result = this.hmac(result, this.service);
    result = this.hmac(result, this.termStr);
    result = this.hmac(result, this.requestToSign()).toString();

    return result;
  };

  authorizationHeader = function () {
    var a = new Array(
      "Credential=" + this.credentials.accessKeyId + "/" + this.credentialScope(),
      "SignedHeaders=" + this.signedHeaders,
      "Signature=" + this.signature()
    );

    return this.algo + " " + a.join(",");
  };

  requestHeader = function () {
    var a = new Array(
      "Authorization: " + this.authorizationHeader(),
      "x-amz-access-token: " + this.credentials.token,
      "x-amz-date: " + this.amzLongDate()
    );

    return a.join("\n");
  };

  queryParameters = function (queryParameterObj) {
    var pieces = [];
    if (queryParameterObj) {
      Object.keys(queryParameterObj)
        .sort()
        .forEach(function (k) {
          return pieces.push(
            k + "=" + encodeURIComponent(queryParameterObj[k])
          );
        });
    }
    return pieces.length > 0 ? pieces.join("&") : "";
  };

  hash = function (str) {
    return CryptoJS.SHA256(str).toString();
  };

  hmac = function (key, data) {
    return CryptoJS.HmacSHA256(data, key);
  };

  amzShortDate = function () {
    return this.amzLongDate().substr(0, 8);
  };

  amzLongDate = function () {
    return this.date
      .toISOString()
      .replace(/[:\-]|\.\d{3}/g, "")
      .substr(0, 13)+'00Z';   
  };

  public
  constructor(credentials, request) {
    this.credentials = credentials;
    this.request = request;
  }

  execute = function () {
    return this.requestHeader();
  };
}
4

1 回答 1

0

使用amazon-sp-api容易得多。这个包包装了所有可用的 API 操作并为您处理所有签名。

于 2022-02-11T01:41:48.200 回答