2015-04-16 3 views
18

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

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.

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

<?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 *.

EDIT: А вот как я использую 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.

ответ

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

} 
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

After you've created the canonical string as described in Format the Query Request, you calculate the signature by creating a hash-based message authentication code (HMAC) using either the HMAC-SHA1 or HMAC-SHA256 protocols. The HMAC-SHA256 protocol is preferred.

The resulting signature must be base-64 encoded and then URI encoded.

+0

Я не уверен, что 'метод делает тело вашего' amazonEncode(), но мне кажется, делать то, что сказано в документации в моем 'знак()' , но используя функции 'base64_encode' и' hash_hmac'. Вы можете объяснить разницу? Кроме того, вы предоставили документацию для AWS, а не MWS. –

+0

Это похоже, генерация подписи для обоих из них. Вам нужно будет URI кодировать сгенерированный base64, что почти то, что делает мой amazonEncode. –

+0

Я завершил результат моего метода 'sign()' в вашей функции 'amazonEncode()', но я все еще получаю ошибку 'SignatureDoesNotMatch'. –

Смежные вопросы