How do I sign a POST request using HMAC-SHA512 and the Python requests library?

后端 未结 1 1892
北海茫月
北海茫月 2020-12-06 01:06

I\'m trying to use Python to access the trading API at poloniex.com, a cryptocurrency exchange. To do this I must follow this prescription:

All calls

相关标签:
1条回答
  • 2020-12-06 01:53

    Create a prepared request; you can add headers to that after the body has been created:

    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)
    

    I changed your params argument to data; for a POST request it is customary to send the parameters in the body, not the URL.

    For the nonce, I'd use a itertools.count() object, seeded from the current time so restarts don't affect it. According to the Poloniex API documentation (which you quoted in your question), the nonce is part of the POST body, not the headers, so put it in the payload dictionary:

    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)
    

    Using int(time.time()) would re-use the same number if you created more than one request per second. The example code provided by Poloniex uses int(time.time()*1000) to make it possible to create a request every microsecond instead, but using your own monotonically increasing counter (seeded from time.time()) is far more robust.

    You can also encapsulate the digest signing process in a custom authentication object; such an object is passed in the prepared request as the last step in preparation:

    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
    

    Use this with your requests calls:

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

    The argument passed in is the secret used in the HMAC digest; you can also pass in a different header name.

    0 讨论(0)
提交回复
热议问题