Проблемы с вычислением подписи для Amazon Marketplace API

Я пытаюсь вычислить подпись для вызовов API Amazon Marketplace, но получаю следующую ошибку:

Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи. Проверьте свой секретный ключ доступа AWS и метод подписи. Обратитесь к сервисной документации для деталей.

Я обернул процесс создания подписи в класс:

<?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()));
}

Как в сторону: я знать учетные данные Marketplace верны, поскольку я вошел в учетную запись и получил ключ доступа, секрет и идентификаторы продавца.

* Я не использую SDK, так как он не поддерживает нужный мне вызов API: SubmitFeed,

20

Решение

Я не уверен, что я изменил, но моя подпись работает сейчас. Ниже приведено содержание класса:

<?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;
}

}
7

Другие решения

Попробуйте эту функцию после вызова вашей функции знака:

  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;
}

Ссылка

После того как вы создали каноническую строку, как описано в разделе Форматирование
Query Request, вы вычисляете подпись, создавая хэш
код аутентификации сообщения (HMAC) с использованием HMAC-SHA1 или
Протоколы HMAC-SHA256. Протокол HMAC-SHA256 является предпочтительным.

Результирующая подпись должна быть закодирована в base-64, а затем в кодировке URI.

2