2014-10-08 100 views
0

我正在尝试在Python中执行WooCommerce API OAuth客户端的基本实现,其文档如下所示:http://docs.woocommercev2.apiary.io/introduction/authentication/over-http。这是我到目前为止有:在python中的WooCommerce API OAuth

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", {}) 

跑的时候,应该产生一个类似的网址:

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 

但URL打开时,我总是得到这样的错误:

{"errors":[{"code":"woocommerce_api_authentication_error","message":"Invalid Signature - provided signature does not match"}]} 

有人可以帮我解决这个问题吗?

回答

2

我发现,即使函数在那里,python没有保留字典的插入顺序。这导致oauth_signature_method出现在oauth_nonce之前,导致它与服务器的签名不同。为了解决这个问题,我重新编制了uksort这个功能:

def uksort(dictionary): 
    return collections.OrderedDict(sorted(dictionary.items(), cmp = cmp)) 
+0

感谢您的支持!我得到的错误:'NameError:全球名称'集合'未定义' – Cmag 2014-12-10 21:41:40

+1

您必须导入脚本顶部的集合模块。 – 2014-12-11 00:39:12