2015-04-16 51 views
18

我试图计算的签名,使亚马逊的市场API调用,但我不断收到以下错误:问题对亚马逊的市场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 *。

编辑:这里是我如何使用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())); 
} 

顺便说一句:我知道市场凭据是正确的,因为我在该帐户已经记录并检索访问密钥,秘密和销售商ID。

*我没有使用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

它们是相似的,它们都是它们的签名生成。您需要对生成的base64进行URI编码,这几乎是我的amazonEncode所做的。 –

+0

我在'amazonEncode()'函数中包装了我的'sign()'方法的结果,但是我仍然遇到'SignatureDoesNotMatch'错误。 –