Python OAuth WooCommerce [英] Python OAuth WooCommerce

查看:18
本文介绍了Python OAuth WooCommerce的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 WooCommerce Python 客户端发出 POST 请求,但是我收到提供的签名不匹配"

I am trying to use a WooCommerce Python client to make a POST request but I get "Provided Signature does not match"

我使用的客户端来自:

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

我在另一个班级这样使用它:

And I use it like this from another class:

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

你能看出我的网址有什么问题吗?感谢您抽出宝贵时间.

Can you see something wrong with my URL ? Thanks for your time.

http://xxxxxxxxx.xx/wc-api/v2/products/?product=%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

推荐答案

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

I used your code as a starting point for my own solution to this problem and had some success! Here's what I did:

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

What I would suggest is ensuring that the parameters are encoded the correct number of times, I found that the parameters needed to be "double encoded" to work. It looks like in this case your parameters (the key and value strings) are not "double encoded" as suggested in the API doc http://woothemes.github.io/woocommerce-rest-api-docs/#authentication

您可以通过尝试一个没有任何参数的简单 GET 请求来测试这一假设,例如我的代码中的参数.如果可行,那么这可能是您的问题.祝你好运!

You can test this hypothesis by trying a simple GET request without any parameters like the one in my code. if that works then that might be your problem. Good luck!

这篇关于Python OAuth WooCommerce的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆