Как мне подписать POST-запрос, используя HMAC-SHA512 и библиотеку запросов Python?

Я пытаюсь использовать Python для доступа к торговому API на бирже криптовалюты poloniex.com. Для этого я должен следовать этому рецепту:

Все вызовы торгового API отправляются через HTTP POST на https://poloniex.com/tradingApi и должны содержать следующие заголовки:

Ключ - Ваш ключ API.
Знак - данные запроса POST, подписанные "секретом" вашего ключа в соответствии с методом HMAC-SHA512.

Кроме того, все запросы должны включать параметр "nonce" POST. Параметр nonce - это целое число, которое всегда должно быть больше предыдущего использованного nonce.

Вот что у меня так далеко. Моя текущая проблема заключается в том, что я не знаю, как скомпилировать URL-адрес 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 ответ

Решение

Создать подготовленный запрос; Вы можете добавить к нему заголовки после создания тела:

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.

Для одноразового использования я бы использовал itertools.count() Объект, посеянный с текущего времени, поэтому перезапуски не влияют на него. Согласно документации API Poloniex (которую вы цитировали в своем вопросе), 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, использует int(time.time()*1000) чтобы сделать возможным создание запроса каждую микросекунду вместо этого, но используя свой собственный монотонно увеличивающийся счетчик (отобранный из time.time()) гораздо надежнее.

Вы также можете инкапсулировать процесс подписания дайджеста в пользовательский объект аутентификации; такой объект передается в подготовленном запросе как последний шаг в подготовке:

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; Вы также можете передать другое имя заголовка.

Другие вопросы по тегам