2015-04-16 18 views
18

sto cercando di calcolare una firma per effettuare chiamate API Amazon, ma continuo a ricevere il seguente errore:Problemi calcolo firma per 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.

ho avvolto il processo di creazione di una firma in un classe:

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

Ma non posso per la vita di me vedere dove sto andando male. Ho seguito la guida nell'API e ho esaminato l'esempio Java e l'antiquato SDK PHP di Marketplace *.

EDIT: Ed ecco come lo sto utilizzando la classe 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())); 
} 

Per inciso: io so le credenziali Marketplace sono corrette come ho collegato al conto e ha recuperato la chiave di accesso, l'ID segreto e il venditore.

* Non sto utilizzando l'SDK in quanto non supporta la chiamata API di cui ho bisogno: SubmitFeed.

risposta

7

io non sono sicuro di quello che ho cambiato, ma la mia generazione firma sta lavorando ora. Di seguito è riportato il contenuto della classe:

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

Prova questa funzione dopo aver chiamato la funzione segno:

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

io non sono sicuro di quello che il corpo del 'amazonEncode()' il metodo sta facendo, ma mi sembra di fare ciò che dice la documentazione nel mio 'segno()' metodo, ma usando le funzioni 'base64_encode' e' hash_hmac'. Puoi spiegare la differenza? Inoltre, la documentazione fornita è per AWS, non MWS. –

+0

È simile, la generazione della firma per entrambi. Avrai bisogno di URI codificare il base64 generato, che è quasi quello che fa il mio amazonEncode. –

+0

Ho avvolto il risultato del mio metodo 'sign()' nella funzione 'amazonEncode()', ma sto ancora ricevendo l'errore 'SignatureDoesNotMatch'. –

Problemi correlati