如何使用 HMAC-SHA512 和 Python 请求库签署 POST 请求?
How do I sign a POST request using HMAC-SHA512 and the Python requests library?
我正在尝试使用 Python 访问 poloniex.com 的交易 API,这是一家加密货币交易所。为此,我必须遵循以下处方:
All calls to the trading API are sent via HTTP POST to https://poloniex.com/tradingApi and must contain the following headers:
Key - Your API key.
Sign - The query's POST data signed by your key's "secret" according to the HMAC-SHA512 method.
Additionally, all queries must include a "nonce" POST parameter. The nonce parameter is an integer which must always be greater than the previous nonce used.
这是我目前所拥有的。我目前的问题是我不知道如何编译 POST url 以便在不先发送不完整请求的情况下对其进行签名。这显然是行不通的。
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)
创建一个prepared request;您可以在创建 body 之后添加 headers:
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 请求,通常在 body 中发送参数,而不是 URL.
对于 nonce,我会使用 itertools.count()
object, seeded from the current time so restarts don't affect it. According to the Poloniex API documentation(您在问题中引用了它),nonce 是 POST body 的一部分,而不是 headers,所以放入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())
会 re-use 相同的数字。 example code provided by Poloniex 使用 int(time.time()*1000)
可以改为每微秒创建一个请求,但是使用您自己的单调递增计数器(从 time.time()
播种)更加稳健。
你也可以将摘要签名过程封装在一个custom authentication object中;这样的 object 作为准备的最后一步在准备好的请求中传递:
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摘要中使用的秘密;您还可以传入不同的 header 名称。
我正在尝试使用 Python 访问 poloniex.com 的交易 API,这是一家加密货币交易所。为此,我必须遵循以下处方:
All calls to the trading API are sent via HTTP POST to https://poloniex.com/tradingApi and must contain the following headers:
Key - Your API key.
Sign - The query's POST data signed by your key's "secret" according to the HMAC-SHA512 method.Additionally, all queries must include a "nonce" POST parameter. The nonce parameter is an integer which must always be greater than the previous nonce used.
这是我目前所拥有的。我目前的问题是我不知道如何编译 POST url 以便在不先发送不完整请求的情况下对其进行签名。这显然是行不通的。
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)
创建一个prepared request;您可以在创建 body 之后添加 headers:
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 请求,通常在 body 中发送参数,而不是 URL.
对于 nonce,我会使用 itertools.count()
object, seeded from the current time so restarts don't affect it. According to the Poloniex API documentation(您在问题中引用了它),nonce 是 POST body 的一部分,而不是 headers,所以放入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())
会 re-use 相同的数字。 example code provided by Poloniex 使用 int(time.time()*1000)
可以改为每微秒创建一个请求,但是使用您自己的单调递增计数器(从 time.time()
播种)更加稳健。
你也可以将摘要签名过程封装在一个custom authentication object中;这样的 object 作为准备的最后一步在准备好的请求中传递:
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摘要中使用的秘密;您还可以传入不同的 header 名称。