python中的WooCommerce API OAuth [英] WooCommerce API OAuth in python
问题描述
我正在尝试按照文档说明在 python 中执行 WooCommerce API OAuth 客户端的基本实现:http://docs.woocommercev2.apiary.io/introduction/authentication/over-http.这是我目前所拥有的:
导入请求随机导入导入字符串导入时间从 hashlib 导入 sha1进口hmac导入二进制文件进口重新从 urllib 导入引用,urlencodedef uksort(d, func):s = {}对于排序中的 k(d.keys(), cmp = func):s[k] = d[k]返回类 WooCommerce(对象):def __init__(self,consumer_key,consumer_secret,endpoint):self.consumer_key = consumer_keyself.consumer_secret = consumer_secretself.endpoint = 端点def _make_request(self, resource, params, method = "GET"):oauth_params = {oauth_consumer_key":self.consumer_key,"oauth_nonce": self._gen_nonce(),"oauth_timestamp": self._gen_timestamp(),"oauth_signature_method": "HMAC-SHA1",}oauth_params["oauth_signature"] = self._gen_signature(resource, dict(params.items() + oauth_params.items()), method)params = dict(params.items() + oauth_params.items())如果方法==GET":打印 self.endpoint + 资源 + "?"+ urlencode(参数)def _gen_nonce(self):ran_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for i in range(32)).encode("base64")alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", ran_string)返回alnum_hashdef _gen_timestamp(self):返回 int(time.time())def _gen_signature(自我,资源,参数,方法):base_request_uri = quote(self.endpoint + resource, safe = "")normalized_params = self._normalize_params(params)sorted_params = uksort(normalized_params, cmp)query_string = "%26".join([key + "%3D" + value for key, value in sorted_params.iteritems()])raw_string = 方法 + "&"+ base_request_uri + "&"+ 查询字符串散列 = hmac.new(self.consumer_secret, raw_string, sha1)返回 binascii.b2a_base64(hashed.digest()).rstrip("\n")def _normalize_params(self, params):归一化 = {}对于 params.iteritems() 中的键、值:键 = 引用(str(键),安全 =")价值=报价(str(价值),安全=")标准化[键] = 值归一化回归如果 __name__ == "__main__":wc = WooCommerce("此处为消费者密钥", "此处为消费者秘密", "您的端点")wc._make_request("/orders", {})
运行时,应该产生一个类似于这样的网址:
<预> <代码> http://www.example.com/wc-api/v2/orders?oauth_signature=0NqB%2BDDtJN2tf2XNkSmXLk2aHro%3D&oauth_consumer_key=CONSUMERKEYHERE40&oauth_signature_method=HMAC-SHA1&oauth_nonce=UzlURlhUTkZaQkM5SEFVNTJWWU5IQ0s3RFZENkZDSFY&oauth_timestamp=1412780008但是打开网址时,总是出现这个错误:
{"errors":[{"code":"woocommerce_api_authentication_error","message":"无效签名 - 提供的签名不匹配"}]}
有人能帮我解决这个问题吗?
我发现,即使函数在那里,python 也没有保持字典的插入顺序.这导致 oauth_signature_method
出现在 oauth_nonce
之前,导致它与服务器的签名不同.为了解决这个问题,我重新制作了 uksort
函数,如下所示:
def uksort(dictionary):返回 collections.OrderedDict(sorted(dictionary.items(), cmp = cmp))
I'm trying to do a basic implementation of the WooCommerce API OAuth client in python following what the documentation says: http://docs.woocommercev2.apiary.io/introduction/authentication/over-http. This is what I have so far:
import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
from urllib import quote, urlencode
def uksort(d, func):
s = {}
for k in sorted(d.keys(), cmp = func):
s[k] = d[k]
return s
class WooCommerce(object):
def __init__(self, consumer_key, consumer_secret, endpoint):
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.endpoint = endpoint
def _make_request(self, resource, params, method = "GET"):
oauth_params = {
"oauth_consumer_key": self.consumer_key,
"oauth_nonce": self._gen_nonce(),
"oauth_timestamp": self._gen_timestamp(),
"oauth_signature_method": "HMAC-SHA1",
}
oauth_params["oauth_signature"] = self._gen_signature(resource, dict(params.items() + oauth_params.items()), method)
params = dict(params.items() + oauth_params.items())
if method == "GET":
print self.endpoint + resource + "?" + urlencode(params)
def _gen_nonce(self):
ran_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for i in range(32)).encode("base64")
alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", ran_string)
return alnum_hash
def _gen_timestamp(self):
return int(time.time())
def _gen_signature(self, resource, params, method):
base_request_uri = quote(self.endpoint + resource, safe = "")
normalized_params = self._normalize_params(params)
sorted_params = uksort(normalized_params, cmp)
query_string = "%26".join([key + "%3D" + value for key, value in sorted_params.iteritems()])
raw_string = method + "&" + base_request_uri + "&" + query_string
hashed = hmac.new(self.consumer_secret, raw_string, sha1)
return binascii.b2a_base64(hashed.digest()).rstrip("\n")
def _normalize_params(self, params):
normalized = {}
for key, value in params.iteritems():
key = quote(str(key), safe = "")
value = quote(str(value), safe = "")
normalized[key] = value
return normalized
if __name__ == "__main__":
wc = WooCommerce("CONSUMER KEY HERE", "CONSUMER SECRET HERE", "YOUR ENDPOINT")
wc._make_request("/orders", {})
Which when ran, should produce a url similar to this:
http://www.example.com/wc-api/v2/orders?oauth_signature=0NqB%2BDDtJN2tf2XNkSmXLk2aHro%3D&oauth_consumer_key=CONSUMERKEYHERE40&oauth_signature_method=HMAC-SHA1&oauth_nonce=UzlURlhUTkZaQkM5SEFVNTJWWU5IQ0s3RFZENkZDSFY&oauth_timestamp=1412780008
But when the URL is opened, I always get this error:
{"errors":[{"code":"woocommerce_api_authentication_error","message":"Invalid Signature - provided signature does not match"}]}
Can anybody help me out with this?
I found out, even though the function is there, python wasn't keeping the insertion order of the dictionary. This caused the oauth_signature_method
to come before the oauth_nonce
causing it to be a different signature that the server's. To fix this, I remade the uksort
function as this:
def uksort(dictionary):
return collections.OrderedDict(sorted(dictionary.items(), cmp = cmp))
这篇关于python中的WooCommerce API OAuth的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!