如何使用HMAC-SHA512和Python请求库签署POST请求?

时间:2017-02-07 21:38:26

标签: python python-requests hmac

我正在尝试使用Python来访问poloniex.com上的交易API,这是一种加密货币交换。要做到这一点,我必须遵循这个处方:

  

所有对交易API的调用都通过HTTP POST发送到https://poloniex.com/tradingApi,并且必须包含以下标题:

     

Key - 您的API密钥。
  Sign - 根据HMAC-SHA512方法,由密钥的“秘密”签名的查询的POST数据。

     

此外,所有查询都必须包含“nonce”POST参数。 nonce参数是一个整数,必须始终大于之前使用的nonce。

这是我到目前为止所拥有的。我目前的问题是我不知道如何编译POST网址,以便可以在不先发送未完成请求的情况下对其进行签名。这显然不起作用。

import requests
import hmac
import hashlib
import time

headers = { 'nonce': '',
            'Key' : 'myKey',
            'Sign': '',}
payload = { 'command': 'returnCompleteBalances',
            'account': 'all'}
secret = 'mySecret'

headers['nonce'] = int(time.time())
response = requests.post( 'https://poloniex.com/tradingApi', params= payload, headers= headers )
headers['Sign'] = hmac.new( secret, response.url, hashlib.sha512)

1 个答案:

答案 0 :(得分:19)

创建prepared request;您可以在创建正文后添加标题:

import requests
import hmac
import hashlib


request = requests.Request(
    'POST', 'https://poloniex.com/tradingApi',
    data=payload, headers=headers)
prepped = request.prepare()
signature = hmac.new(secret, prepped.body, digestmod=hashlib.sha512)
prepped.headers['Sign'] = signature.hexdigest()

with requests.Session() as session:
    response = session.send(prepped)

我将params参数更改为data;对于POST请求,通常会在正文中发送参数,而不是URL。

对于nonce,我使用itertools.count() object,从当前时间播种,因此重新启动不会影响它。根据{{​​3}}(你在问题中引用),nonce是POST主体的一部分,而不是标题,所以把它放在payload字典中:

from itertools import count
import time

# store as a global variable
NONCE_COUNTER = count(int(time.time() * 1000))

# then every time you create a request
payload['nonce'] = next(NONCE_COUNTER)

如果您每秒创建多个请求,则使用int(time.time())会重复使用相同的数字。 Poloniex API documentation使用int(time.time()*1000)来实现每微秒创建一个请求,但使用您自己的单调递增计数器(从time.time()播种)更加强大。

您还可以在example code provided by Poloniex中封装摘要签名流程;这样的对象在准备好的请求中作为准备的最后一步传递:

import hmac
import hashlib

class BodyDigestSignature(object):
    def __init__(self, secret, header='Sign', algorithm=hashlib.sha512):
        self.secret = secret
        self.header = header
        self.algorithm = algorithm

    def __call__(self, request):
        body = request.body
        if not isinstance(body, bytes):   # Python 3
            body = body.encode('latin1')  # standard encoding for HTTP
        signature = hmac.new(self.secret, body, digestmod=self.algorithm)
        request.headers[self.header] = signature.hexdigest()
        return request

requests来电时使用此功能:

response = requests.post(
    'https://poloniex.com/tradingApi',
    data=payload, headers=headers, auth=BodyDigestSignature(secret))

传入的论据是HMAC摘要中使用的秘密;您也可以传入不同的标题名称。