简体   繁体   English

python中的WooCommerce API OAuth

[英]WooCommerce API OAuth in python

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 . 我正在尝试按照文档中的说法在python中执行WooCommerce API OAuth客户端的基本实现: 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: 哪个运行时,应该生成类似这样的url:

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: 但是当URL打开时,我总是会收到此错误:

{"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. 我发现,即使函数在那里,python也没有保持字典的插入顺序。 This caused the oauth_signature_method to come before the oauth_nonce causing it to be a different signature that the server's. 这导致oauth_signature_methodoauth_signature_method之前oauth_nonce导致它与服务器的签名不同。 To fix this, I remade the uksort function as this: 为了解决这个问题,我将uksort函数重新设置为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM