Python中的OAuth WooCommerce(Python OAuth WooCommerce

2019-10-21 19:50发布

我试图用一个WooCommerce Python客户端进行POST请求,但我得到“提供的签名不匹配”

我使用的客户端是:

在python WooCommerce API的OAuth

这是我的客户:

#!/usr/bin/env python

import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
import collections
from urllib import quote, urlencode


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

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)
        elif method == "POST":
            print self.endpoint + resource + "?" + urlencode(params)
            req = urllib.request.Request(self.endpoint + resource + "?" + urlencode(params))
            open = urllib.request.urlopen(req)
            requestContent = open.read()
            #print(open)

    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)
        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

我用它像这样从另一个类:

woo_client = WooCommerce('ck_7bb1951bee7454b2e29bf5eef9205e0e', 'cs_155cd9420201c0a7e140bebd6a9794c7', 'http://dima.bg/wc-api/v2')

data = {
               "product": {
                "title": "testname",
               }
           }    
result = self.woo_client._make_request("/products/", data, 'POST')

你能看到什么毛病我的网址是什么? 谢谢你的时间。

HTTP://xxxxxxxxx.xx/wc-api/v2/products/产物=%7B%27title%27%3A +%27testname%27%7D&oauth_nonce = NThWODczRFIyWkxRNFZOVkUxNFdRSVo0QjFSNllIVFk&oauth_timestamp = 1423647865&oauth_consumer_key = ck_7bb1951bee7454b2e29bf5eef9205e0e&oauth_signature_method = HMAC-SHA1&oauth_signature = 3PSnEEf08gFthIRAr8AUKQiDjco%3D

Answer 1:

我用你的代码作为一个起点,我自己解决这个问题,并取得了一些成功! 这是我做的:

import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
from urllib import quote, urlencode
import httplib2
from collections import OrderedDict

def key_compare(a, b):
    return cmp(a[0], b[0])

class Restful_Client(object):
    """docstring for Restful_Client"""
    def __init__(self, endpoint, consumer_key, consumer_secret):
        super(Restful_Client, self).__init__()
        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_version':'1.0'
        }
        oauth_params['oauth_signature'] = self.gen_signature(
            resource,
            OrderedDict( params.items() + oauth_params.items() ),
            method
        )
        params = OrderedDict( params.items() + oauth_params.items() )
        clean_params = self.sort_params(self.normalize_params(params))

        uri = endpoint + resource
        p_string = urlencode(clean_params)

        print 'p string:'
        print '\n'.join(p_string.split('&'))

        return httplib2.Http().request(uri + '?' + p_string)

    def gen_signature(self, resource, params, method):
        base_request_uri = quote(self.endpoint + resource, safe = "")
        clean_params = self.sort_params(
            self.normalize_params(
                self.normalize_params(
                    params
                )
            )
        )
        query_string = '%26'.join([
            key + '%3D' + value\
            for key, value in clean_params.iteritems()
        ])
        raw_string = '&'.join([method, base_request_uri, query_string]) 
        print "raw string: "
        print '\n'.join(raw_string.split('%26'))
        hashed = hmac.new(self.consumer_secret, raw_string, sha1)
        return binascii.b2a_base64( hashed.digest() )[:-1]

    def normalize_string(self, string):
        return quote(str(string), safe="")

    def normalize_params(self, params):
        return OrderedDict( [
            (self.normalize_string(key), self.normalize_string(value))\
            for key, value \
            in params.iteritems()
        ])

    def sort_params(self, params):
        return OrderedDict(sorted(
            params.iteritems(),
            cmp=key_compare
        ))

    def gen_timestamp(self):
        return int(time.time())
        # return 1429451603

    def gen_nonce(self):
        return hex(self.gen_timestamp())
        #todo: make this more secure

if __name__ == "__main__":
    store_url = '<STORE URL HERE>'
    api_base = 'wc-api'
    api_ver = 'v2'
    endpoint = "%s/%s/%s/" % (store_url, api_base, api_ver)

    consumer_key = '<CK HERE>'
    consumer_secret = '<CS HERE>'

    resource = 'customers'
    parameters = {
        # 'fields':'id,first_name'
    }

    rc = Restful_Client(endpoint, consumer_key, consumer_secret)
    r, c = rc.make_request(resource, parameters, 'GET')
    print r
    print c

我的建议是,确保对参数进行编码的正确的次数,我发现这是所需的参数“双重编码”工作。 它看起来像在这种情况下,您的参数(key和value字符串)是作为API文档建议不要“双编码” http://woothemes.github.io/woocommerce-rest-api-docs/#authentication

您可以通过尝试没有像在我的代码中的任何参数的简单GET请求验证这一假说。 如果工作那么这可能是你的问题。 祝好运!



文章来源: Python OAuth WooCommerce