计算亚马逊商城API签名的问题

时间:2015-04-16 15:41:11

标签: php amazon-mws amazon-marketplace

我正在尝试计算签名以进行亚马逊商城API调用,但我不断收到以下错误:

  

我们计算的请求签名与您提供的签名不符。检查您的AWS Secret Access Key和签名方法。有关详细信息,请参阅服务文档。

我已将签名创建过程包装到一个类中:

<?php
namespace App\Marketplace\Amazon;

class Signature
{
    protected $signedString;

    public function __construct($url, array $parameters, $secretAccessKey)
    {
        $stringToSign = $this->calculateStringToSign($url, $parameters);

        $this->signedString = $this->sign($stringToSign, $secretAccessKey);
    }

    protected function calculateStringToSign($url, array $parameters)
    {
        $url = parse_url($url);

        $string = "POST\n";
        $string .= $url['host'] . "\n";
        $string .= $url['path'] . "\n";
        $string .= $this->getParametersAsString($parameters);

        return $string;
    }

    protected function sign($data, $secretAccessKey)
    {
        return base64_encode(hash_hmac('sha256', $data, $secretAccessKey, true));
    }

    protected function getParametersAsString(array $parameters)
    {
        uksort($parameters, 'strcmp');

        $queryParameters = [];

        foreach ($parameters as $key => $value) {
            $queryParameters[$key] = $this->urlEncode($value);
        }

        return http_build_query($queryParameters);
    }

    protected function urlEncode($value)
    {
        return str_replace('%7E', '~', rawurlencode($value));
    }

    public function __toString()
    {
        return $this->signedString;
    }
}

但我不能为我的生活看到我出错的地方。我已经按照API中的指南,查看了Java示例以及过时的Marketplace PHP SDK *。

编辑:以下是我使用Signature课程的方式:

$version = '2011-07-01';

$url = 'https://mws.amazonservices.com/Sellers/'.$version;

$timestamp = gmdate('c', time());

$parameters = [
    'AWSAccessKeyId' => $command->accessKeyId,
    'Action' => 'GetAuthToken',
    'SellerId' => $command->sellerId,
    'SignatureMethod' => 'HmacSHA256',
    'SignatureVersion' => 2,
    'Timestamp' => $timestamp,
    'Version' => $version,
];

$signature = new Signature($url, $parameters, $command->secretAccessKey);

$parameters['Signature'] = strval($signature);

try {
    $response = $this->client->post($url, [
        'headers' => [
            'User-Agent' => 'my-app-name',
        ],
        'body' => $parameters,
    ]);

    dd($response->getBody());
} catch (\Exception $e) {
    dd(strval($e->getResponse()));
}

暂时不说:我知道市场凭据是正确的,因为我已登录帐户并检索了访问密钥,密码和卖家ID。

*我没有使用SDK,因为它不支持我需要的API调用:SubmitFeed

2 个答案:

答案 0 :(得分:7)

我不确定我改变了什么,但我的签名一代现在正在运作。以下是该课程的内容:

<?php
namespace App\Marketplace\Amazon;

class Signature
{
    /**
     * The signed string.
     *
     * @var string
     */
    protected $signedString;

    /**
     * Create a new signature instance.
     *
     * @param  string  $url
     * @param  array   $data
     * @param  string  $secretAccessKey
     */
    public function __construct($url, array $parameters, $secretAccessKey)
    {
        $stringToSign = $this->calculateStringToSign($url, $parameters);

        $this->signedString = $this->sign($stringToSign, $secretAccessKey);
    }

    /**
     * Calculate the string to sign.
     *
     * @param  string  $url
     * @param  array   $parameters
     * @return string
     */
    protected function calculateStringToSign($url, array $parameters)
    {
        $url = parse_url($url);

        $string = "POST\n";
        $string .= $url['host']."\n";
        $string .= $url['path']."\n";
        $string .= $this->getParametersAsString($parameters);

        return $string;
    }

    /**
     * Computes RFC 2104-compliant HMAC signature.
     *
     * @param  string  $data
     * @param  string  $secretAccessKey
     * @return string
     */
    protected function sign($data, $secretAccessKey)
    {
        return base64_encode(hash_hmac('sha256', $data, $secretAccessKey, true));
    }

    /**
     * Convert paremeters to URL-encoded query string.
     *
     * @param  array  $parameters
     * @return string
     */
    protected function getParametersAsString(array $parameters)
    {
        uksort($parameters, 'strcmp');

        $queryParameters = [];

        foreach ($parameters as $key => $value) {
            $key = rawurlencode($key);
            $value = rawurlencode($value);

            $queryParameters[] = sprintf('%s=%s', $key, $value);
        }

        return implode('&', $queryParameters);
    }

    /**
     * The string representation of this signature.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->signedString;
    }

}

答案 1 :(得分:2)

调用您的签名功能后尝试此功能:

  function amazonEncode($text)
  {
    $encodedText = "";
    $j = strlen($text);
    for($i=0;$i<$j;$i++)
    {
      $c = substr($text,$i,1);
      if (!preg_match("/[A-Za-z0-9\-_.~]/",$c))
      {
        $encodedText .= sprintf("%%%02X",ord($c));
      }
      else
      {
        $encodedText .= $c;
      }
    }
    return $encodedText;
  }

Reference

  

在您创建规范字符串后,如格式化   查询请求,您可以通过创建基于哈希的方法来计算签名   消息认证码(HMAC)使用HMAC-SHA1或   HMAC-SHA256协议。 HMAC-SHA256协议是首选。

     

生成的签名必须是base-64编码,然后进行URI编码。