2017-02-07 2 views
5

J'essaie d'utiliser Python pour accéder à l'API de trading sur poloniex.com, un échange de crypto-monnaie. Pour ce faire, je dois suivre cette prescription:Comment puis-je signer une requête POST à ​​l'aide de HMAC-SHA512 et de la bibliothèque de requêtes Python?

Tous les appels à l'API de trading sont envoyés via HTTP POST à ​​https://poloniex.com/tradingApi et doit contenir les en-têtes suivants:

Key - Votre clé API.
Signe - Les données POST de la requête sont signées par le "secret" de votre clé selon la méthode HMAC-SHA512.

De plus, toutes les requêtes doivent inclure un paramètre POST "nonce". Le paramètre nonce est un entier qui doit toujours être supérieur au nonce précédent utilisé.

Voici ce que j'ai jusqu'à présent. Mon problème actuel est que je ne sais pas comment compiler l'url POST afin qu'il puisse être signé sans envoyer la requête incomplète en premier. Cela ne fonctionne évidemment pas.

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) 

Répondre

11

Créer un prepared request; vous pouvez ajouter des en-têtes que après que le corps a été créé:

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) 

j'ai changé vos arguments params à data; pour une requête POST, il est habituel d'envoyer les paramètres dans le corps, pas l'URL.

Pour le nonce, j'utiliserais un itertools.count() object, semé à partir de l'heure actuelle afin que les redémarrages ne l'affectent pas. Selon le Poloniex API documentation (que vous avez cité dans votre question), le nonce fait partie du corps POST, pas les en-têtes, donc le mettre dans le payload dictionnaire:

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) 

En utilisant int(time.time()) serait réutiliser le même numéro si vous avez créé plus d'une requête par seconde. Le example code provided by Poloniex utilise int(time.time()*1000) pour permettre de créer une requête toutes les microsecondes à la place, mais en utilisant votre propre compteur augmentant de façon monotone (semé de time.time()) est beaucoup plus robuste.

Vous pouvez également encapsuler le processus de signature digest dans un custom authentication object; un tel objet est passé dans la requête préparée comme la dernière étape de préparation:

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 

Utilisez avec vos requests appels:

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

L'argument transmis est le secret utilisé dans le HMAC digest; vous pouvez également passer un nom d'en-tête différent.

+0

C'était tellement rapide, merci beaucoup! – Werhli

+0

@MartijnPieters lorsque j'exécute ceci, j'obtiens une erreur disant: l'objet 'Request' n'a pas d'attribut 'body'. pour cette ligne: signature = hmac.new (secret, request.body, digestmod = hashlib.sha512) –

+0

@abcla corrigé –