2014-08-28 251 views
2

我一直試圖讓這個工作幾個小時。其他問題的解決方案都沒有工作。亞馬遜API MWS SignatureDoesNotMatch

我想要做的是獲得我在亞馬遜的訂單清單。爲此,我正在致電亞馬遜MWS。然而,這是錯誤消息我得到:

<?xml version="1.0"?> 
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01"> 
    <Error> 
    <Type>Sender</Type> 
    <Code>SignatureDoesNotMatch</Code> 
    <Message>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.</Message> 
    </Error> 
    <RequestID>03686743-15a6-4207-b0b7-316d1e4e5c8f</RequestID> 
</ErrorResponse> 

要找出什麼是錯的,我去到亞馬遜MWS便籤和使用相同的值,甚至時間戳(我想你有15分鐘,直到它過期),並比較簽名。他們是一樣的。但是,我的程序仍然得到相同的錯誤,而便箋簿完美工作。

這裏是所有代碼:

import sys, os, base64, datetime, hashlib, hmac, urllib 
from time import gmtime, strftime 
from requests import request 
import xml.etree.ElementTree as ET 

def get_timestamp(): 
    """Return correctly formatted timestamp""" 
    return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime()) 

def calc_signature(): 
    """Calculate signature to send with request""" 
    sig_data = method + '\n' + domain.replace('https://', '').lower() + '\n' + URI + '\n' + request_description 
    hmac_obj = hmac.new(str(SECRET_KEY), sig_data, hashlib.sha256) 
    return urllib.quote(base64.b64encode(hmac_obj.digest()), safe='-_.~') 

SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 
AWS_ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxx' 
SELLER_ID = 'xxxxxxxxxxxxxxxxxxxxxxx' 
MARKETPLACE_ID = 'xxxxxxxxxxxxxxx' 

Action = 'ListOrders' 
SignatureMethod = 'HmacSHA256' 
SignatureVersion = '2' 
Timestamp = get_timestamp() 
Version = '2013-09-01' 
CreatedAfter = '2014-08-26T23:00:57Z' # TODO -1 day 
URI = '/Orders/2013-09-01' 
domain = 'https://mws.amazonservices.co.uk' 
method = 'POST' 

payload = {'AWSAccessKeyId': AWS_ACCESS_KEY, 
      'Action': Action, 
      'SellerId': SELLER_ID, 
      'SignatureVersion': SignatureVersion, 
      'Timestamp': Timestamp, 
      'Version': Version, 
      'SignatureMethod': SignatureMethod, 
      'CreatedAfter': '2014-08-26T23:00:00Z', 
      'MarketplaceId.Id.1': MARKETPLACE_ID 
      } 

request_description = '&'.join(['%s=%s' % (k, urllib.quote(payload[k], safe='-_.~').encode('utf-8')) for k in sorted(payload)]) 

sig = calc_signature() 

url = '%s%s?%s&Signature=%s' % (domain, URI, request_description, urllib.quote(sig)) 
headers = {'Host': 'amazonwebservices.co.uk', 'Content-Type': 'text/xml', 'x-amazon-user-agent': 'python-requests/1.2.0 (Language=Python)'} 

response = request(method, url, headers=headers) 
print response.content 

這裏是sig_data打印在calc_signature()

POST 
mws.amazonservices.co.uk 
/Orders/2013-09-01 
AWSAccessKeyId=xxxxxxxxxxxxx&Action=ListOrders&CreatedAfter=2014-08-26T23%3A00%3A00Z&MarketplaceId.Id.1=xxxxxxxxxxxxx&SellerId=xxxxxxxxxxxxxxx&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-08-28T15%3A50%3A34Z&Version=2013-09-01 

這裏是url打印:

https://mws.amazonservices.co.uk/Orders/2013-09-01?AWSAccessKeyId=xxxxxxxxxxxx&Action=ListOrders&CreatedAfter=2014-08-26T23%3A00%3A00Z&MarketplaceId.Id.1=xxxxxxxxxxxx&SellerId=xxxxxxxxxxxxx&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-08-28T15%3A50%3A34Z&Version=2013-09-01&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 

我徹底擺脫了在這一點上的想法。我有三倍檢查我的密鑰,訪問密鑰,賣家ID和市場ID是否正確。

任何幫助將大規模,大規模讚賞!

+0

你是' urllib.quote'簽名兩次。在你的'calc_signature'裏面和外面。 – 2015-02-02 12:53:03

回答

2

我知道這是遲了幾個月,但儘管知道我的簽名是正確的,並且發現它實際上是POST執行是問題而不是簽名,但我仍然有同樣的問題。如果亞馬遜無法理解你的參數,它會拋出HTTP 403錯誤,並告訴你你的簽名是錯誤的,即使它不是。我不能告訴你爲什麼是這樣工作的,但嘗試跳過請求庫和做後續的使用urllib.request裏建立你的網址,而不是它爲我工作後:

#using python 3.4 

import urllib.request 

#... your code from before... 

headers = {'Host': 'mws.amazonservices.com', 'Content-Type': 'text/xml', 'x-amazon-user-agent': 'SomeApp/1.1 (Language=Python)'} 
req = urllib.request.Request(method=method,url=url,headers=headers) 
response = urllib.request.urlopen(req) 
the_page = response.read() 
print(the_page) 

#As seen here: https://docs.python.org/3/howto/urllib2.html#data 

如果不這樣做,再來看看你如何編碼所有東西,也許用urllib.parse涉獵。

快樂亞馬遜!

1

calc_signature函數中,safe參數不允許+/,它們在base64輸出字符集中是允許的。因此,它對它們進行百分比編碼,然後這些百分比在查詢字符串中得到進一步的perecnt編碼,如%25

我做了一些修改,所以這裏的所有代碼:

import sys, os, base64, datetime, hashlib, hmac, urllib 
from time import gmtime, strftime 
from requests import request 
import xml.etree.ElementTree as ET 

def get_timestamp(): 
    """Return correctly formatted timestamp""" 
    return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime()) 

def calc_signature(method, domain, URI, request_description, key): 
    """Calculate signature to send with request""" 
    sig_data = method + '\n' + \ 
     domain.lower() + '\n' + \ 
     URI + '\n' + \ 
     request_description 

    hmac_obj = hmac.new(key, sig_data, hashlib.sha256) 
    digest = hmac_obj.digest() 

    return urllib.quote(base64.b64encode(digest), safe='-_+=/.~') 

SECRET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' 
AWS_ACCESS_KEY = 'XXXXXXXXXXXXXX' 
SELLER_ID = 'XXXXXXXXXXXXX' 
MARKETPLACE_ID = 'XXXXXXXXXXXX' 

Action = 'ListOrders' 
SignatureMethod = 'HmacSHA256' 
SignatureVersion = '2' 
Timestamp = get_timestamp() 
Version = '2013-09-01' 
CreatedAfter = '2013-08-26T23:00:57Z' 
URI = '/Orders/2013-09-01' 
domain = 'mws.amazonservices.com' 
proto = 'https://' 
method = 'POST' 

payload = { 
    'AWSAccessKeyId': AWS_ACCESS_KEY, 
    'Action': Action, 
    'SellerId': SELLER_ID, 
    'SignatureVersion': SignatureVersion, 
    'Timestamp': Timestamp, 
    'Version': Version, 
    'SignatureMethod': SignatureMethod, 
    'CreatedAfter': CreatedAfter, 
    'MarketplaceId.Id.1': MARKETPLACE_ID 
} 

request_description = '&'.join(['%s=%s' % (k, urllib.quote(payload[k], safe='-_.~').encode('utf-8')) for k in sorted(payload)]) 

sig = calc_signature(method, domain, URI, request_description, SECRET_KEY) 

url = '%s%s?%s&Signature=%s' % \ 
    (proto+domain, URI, request_description, urllib.quote(sig)) 

headers = { 
    'Host': domain, 
    'Content-Type': 'text/xml', 
    'x-amazon-user-agent': 'python-requests/1.2.0 (Language=Python)' 
} 

response = request(method, url, headers=headers) 

print response.content 
-1

這似乎爲我工作

foreach ($params as $key => $val) { 
    if(in_array($key, array('CreatedAfter', 'CreatedBefore', 'LastUpdatedAfter', 'LastUpdatedBefore'))) { 
     $key = str_replace("%7E", "~", rawurlencode($key)); 
     $val = str_replace("%7E", "~", urlencode($val)); 
    } else { 
     $key = str_replace("%7E", "~", rawurlencode($key)); 
     $val = str_replace("%7E", "~", rawurlencode($val)); 
    } 

    $url[] = "{$key}={$val}"; 
} 

通知我加的是進行urlencode()方法