当前位置: 首页 > 知识库问答 >
问题:

Python OAuth WooCommerce

严欣怡
2023-03-14

我正试图使用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/?product={'title':'testname'}

共有1个答案

微生高谊
2023-03-14

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

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

我的建议是确保参数的编码次数正确,我发现参数需要“双重编码”才能工作。在这种情况下,您的参数(键和值字符串)似乎不是API文档中建议的“双重编码”http://woothemes.github.io/woocommerce-rest-api-docs/#authentication

您可以通过尝试一个简单的GET请求来验证这个假设,而不需要任何参数,比如我的代码中的参数。如果这有效,那可能是你的问题。祝你好运

 类似资料:

相关问答

相关文章

相关阅读