Questions calcul de la signature pour L'API Amazon Marketplace

j'essaie de calculer une signature pour faire des appels D'API Amazon Marketplace, mais j'obtiens toujours l'erreur suivante:

la signature de la demande que nous avons calculée ne correspond pas à la signature que vous avez fournie. Vérifiez votre clé D'accès secrète AWS et votre méthode de signature. Consultez la documentation du service pour plus de détails.

j'ai enveloppé le processus de création de signature dans une classe:

<?php
namespace AppMarketplaceAmazon;

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 = "POSTn";
        $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;
    }
}

mais je ne peux pas, pour ma vie, voir où je vais mauvais. J'ai suivi le guide dans L'API, et j'ai regardé L'exemple de Java ainsi que le Vieux Marché PHP SDK*.

EDIT: et voici comment j'utilise le Signature catégorie:

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

comme une mise de côté: I les informations D'identification du marché sont correctes car je me suis connecté au compte et j'ai récupéré la clé d'accès, le secret, et les identifiants du vendeur.

* Je n'utilise pas le SDK car il ne supporte pas l'appel API dont j'ai besoin: SubmitFeed.

20
demandé sur Martin Bean 2015-04-16 18:41:10

2 réponses

Je ne suis pas sûr de ce que j'ai changé, mais ma génération de signature fonctionne maintenant. Ci-dessous le contenu de la 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;
    }

}
7
répondu Martin Bean 2015-04-18 23:27:43

essayez cette fonction après avoir appelé votre fonction de signe:

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

Référence

après avoir créé la chaîne canonique comme décrit dans le Format Requête de requête, vous calculez la signature en créant une base de hachage code d'authentification de message (HMAC) utilisant soit le HMAC-SHA1, soit Protocoles HMAC-SHA256. Le protocole HMAC-SHA256 est préféré.

la signature résultante doit être codée base-64 et ensuite URI encodage.

2
répondu Arun Poudel 2015-04-18 21:09:34