亚马逊MWS签名问题

Amazon MWS signature issue

我正在尝试实施亚马逊 MWS API。当我调用特定 URL 时,出现以下错误

The request signature we calculated does not match the signature you provided. 
Check your AWS Secret Access Key and signing method

我已经尝试了所有可能的 Whosebug 解决方案和其他一些解决方案,但我无法解决此问题。这是我的 PHP 代码

$param = array();
$param['AWSAccessKeyId'] = 'AKIAJ76NICWXXXXXXXXX';
$param['Action'] = 'GetReportRequestList';
$param['SellerId'] = 'A4XLZYW8XXXXX';
$param['SignatureMethod'] = 'HmacSHA256';
$param['SignatureVersion'] = '2';
$param['Timestamp'] = gmdate("Y-m-d\TH:i:s.\0\0\0\Z", time());
$param['Version'] = '2011-10-01';
$param['MarketplaceId'] = 'A2EUQ1WTGCTBG2';

$url = array();
foreach ($param as $key => $val) {
    $key = str_replace("%7E", "~", rawurlencode($key));
    $val = str_replace("%7E", "~", rawurlencode($val));
    $url[] = "{$key}={$val}";
}

uksort($url, 'strcmp');

$arr = implode('&', $url);

$sign = 'POST' . "\n";
$sign .= 'mws.amazonservices.com' . "\n";
$sign .= $arr;

$signature = hash_hmac("sha256", $sign, "+vWJ/hISrN2IyRMnaTHTaXXXXXXXX");

$link = "https://mws.amazonservices.com?";
$link .= $arr . "&Signature=" . urlencode(base64_encode($signature));

未测试。我修改了您的代码以在对参数进行编码之前进行排序,并在指定 RFC3986 编码时将 str_replace/rawurlencode 替换为 http_build_query。希望这对你有用

$param = array();
$param['AWSAccessKeyId'] = 'AKIAJ76NICWXXXXXXXXX';
$param['Action'] = 'GetReportRequestList';
$param['SellerId'] = 'A4XLZYW8XXXXX';
$param['SignatureMethod'] = 'HmacSHA256';
$param['SignatureVersion'] = '2';
$param['Timestamp'] = gmdate("Y-m-d\TH:i:s.\0\0\0\Z", time());
$param['Version'] = '2011-10-01';
$param['MarketplaceId'] = 'A2EUQ1WTGCTBG2';
uksort($param, 'strcmp');
$sign = "POST\nmws.amazonservices.com\n/\n" . http_build_query($param, '', '&', PHP_QUERY_RFC3986);
$signature = base64_encode(hash_hmac("sha256", $sign, "+vWJ/hISrN2IyRMnaTHTaXXXXXXXX", true));
$param['Signature'] = $signature;
$ctx = stream_context_create([
    "http" => [
        "method" => "POST",
        "header" => "Content-type: application/x-www-form-urlencoded\r\n\r\n", 
        "content" => http_build_query($param)
    ]
]);
$result = file_get_contents("https://mws.amazonservices.com/?", false, $ctx);

编辑: 这是亚马逊 MWS 文档的 link。第 16 页描述了签名过程并解释了我的修改。

这是解决方案。

$params = array(
    'AWSAccessKeyId' => "AKIAJB4PTEUXXXXXX",
    'Action' => "GetReportRequestList",
    'SellerId' => "A4XLZXXXXXX",
    'SignatureMethod' => "HmacSHA256",
    'SignatureVersion' => "2",
    'Timestamp' => gmdate("Y-m-d\TH:i:s.\0\0\0\Z", time()),
    'Version' => "2009-01-01",
    'MarketplaceId' => "ATVPDKIKX0DER",
);

// Sort the URL parameters
$url_parts = array();
foreach (array_keys($params) as $key)
    $url_parts[] = $key . "=" . str_replace('%7E', '~', rawurlencode($params[$key]));

sort($url_parts);

// Construct the string to sign
$url_string = implode("&", $url_parts);
$string_to_sign = "GET\nmws.amazonservices.com\n/\n" . $url_string;

// Sign the request
$signature = hash_hmac("sha256", $string_to_sign, "7D/QEUYXrJ/XQYyAAMPgiwTXXXXXX", TRUE);

// Base64 encode the signature and make it URL safe
$signature = urlencode(base64_encode($signature));

$url = "https://mws.amazonservices.com/" . '?' . $url_string . "&Signature=" . $signature;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);

$parsed_xml = simplexml_load_string($response);