2015-04-16 7 views
18

Ich versuche, eine Signatur zu berechnen Amazon Marketplace API-Aufrufe zu machen, aber ich bekomme immer folgende Fehlermeldung:Probleme Berechnung Signatur für 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.

ich den Signaturerstellungsprozesses in eine eingewickelt habe Klasse:

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

Aber ich kann nicht für das Leben von mir sehen, wo ich falsch liege. Ich habe den Leitfaden in der API verfolgt und das Java-Beispiel sowie das veraltete Marketplace PHP SDK * betrachtet.

EDIT: Und hier ist, wie ich die Signature Klasse bin mit:

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

Als Nebenwirkung: Ich wissen die Marktdaten richtig sind, wie ich in dem Konto angemeldet haben und hat die Zugriffsschlüssel-, Geheim- und Verkäufer-IDs abgerufen.

* Ich verwende nicht das SDK, da es den API-Aufruf nicht unterstützt, den ich brauche: SubmitFeed.

Antwort

7

Ich bin mir nicht sicher, was ich geändert habe, aber meine Unterschrift Generation arbeitet jetzt. Im Folgenden finden Sie die Inhalte der Klasse:

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

diese Funktion Versuchen nach dem Zeichen-Funktion aufrufen:

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

Ich bin nicht sicher, was der Körper Ihres 'amazonEncode()' Methode tut, aber ich scheine zu tun, was die Dokumentation in meinem 'Zeichen sagt()' Methode, aber mit den Funktionen 'base64_encode' und' hash_hmac'. Kannst du den Unterschied erklären? Außerdem ist die von Ihnen bereitgestellte Dokumentation für AWS und nicht für MWS. –

+0

Es ist ähnlich, die Signatur-Generation für beide. Sie müssen URI das generierte base64 kodieren, was fast mein amazonEncode ist. –

+0

Ich habe das Ergebnis meiner 'sign()' Methode in Ihrer 'amazonEncode()' Funktion eingeschlossen, aber ich bekomme immer noch 'SignatureDoesNotMatch' Fehler. –