我正在尝试为kraken写一个不错的身份验证帮助程序。我希望它尽可能自动,所以需要:
time.time()*1000
)我根据this答案写了显而易见的代码:
class KrakenAuth(AuthBase):
"""a requests-module-compatible auth module for kraken.com"""
def __init__(self, key, secret):
self.api_key = key
self.secret_key = secret
def __call__(self, request):
#print("Auth got a %r" % type(request))
nonce = int(1000*time.time())
request.data = getattr(request, 'data', {})
request.data['nonce'] = nonce
request.prepare()
message = request.path_url + hashlib.sha256(str(nonce) + request.body).digest()
hmac_key = base64.b64decode(self.secret_key)
signature = hmac.new(hmac_key, message, hashlib.sha512).digest()
signature = base64.b64encode(signature)
request.headers.update({
'API-Key': self.api_key,
'API-Sign': signature
})
return request
他们(从另一个对象的包装器方法)调用它们,就像:
def _request(self, method, url, **kwargs):
if not self._auth:
self._auth = KrakenAuth(key, secret)
if 'auth' not in kwargs:
kwargs['auth'] = self._auth
return self._session.request(method, URL + url, **kwargs)
...但是它不起作用。已注释掉的print()
语句表明它得到的是PreparedRequest
对象而不是Request
对象,因此对request.prepare()
的调用就是对PreparedRequest.prepare
的调用nothing useful,因为没有request.data
,因为它已经被转换为body
属性。
答案 0 :(得分:1)
您无法访问请求的data
属性,因为身份验证对象已应用到requests.PreparedRequest()
instance,而没有.data
属性。
Session.request()
call(由所有request.<method>
和session.<method>
调用使用)的正常流程如下:
Request()
实例Session.prepare_request()
,后者首先将会话存储的基值与原始调用的参数合并,然后PreparedRequest()
instance PreparedRequest.prepare()
method,传入来自Request
实例和会话的合并数据。prepare()
方法调用各种self.prepare_*
方法,包括PreparedRequest.prepare_auth()
。PreparedRequest.prepare_auth()
调用auth(self)
,使身份验证对象有机会将信息附加到请求。不幸的是,在此流程中,data
和PreparedRequest.prepare()
以外的任何人都无法使用原始PreparedRequest.prepare_body()
映射,在这些方法中,映射是局部变量。您不能从身份验证对象访问它。
您的选择如下:
再次解码正文,并使用更新的映射调用prepare_body()
。
不使用身份验证对象,而是使用答案中的其他路径;明确创建准备好的请求并首先处理data
。
使用Python堆栈玩地狱,并从两帧以上的prepare()
方法中提取本地语言。我真的不推荐这条路。
为了使认证方法更好地封装,我将进行解码/重新编码;通过重用PreparedRequest.prepare_body()
,后者很简单:
import base64
import hashlib
import hmac
import time
try:
# Python 3
from urllib.parse import parse_qs
except ImportError:
# Python 2
from urlparse import parse_qs
from requests import AuthBase
URL_ENCODED = 'application/x-www-form-urlencoded'
class KrakenAuth(AuthBase):
"""a requests-module-compatible auth module for kraken.com"""
def __init__(self, key, secret):
self.api_key = key
self.secret_key = secret
def __call__(self, request):
ctheader = request.headers.get('Content-Type')
assert (
request.method == 'POST' and (
ctheader == URL_ENCODED or
requests.headers.get('Content-Length') == '0'
)
), "Must be a POST request using form data, or empty"
# insert the nonce in the encoded body
data = parse_qs(request.body)
data['nonce'] = nonce
request.prepare_body(data, None, None)
body = request.body
if not isinstance(body, bytes): # Python 3
body = body.encode('latin1') # standard encoding for HTTP
message = request.path_url + hashlib.sha256(b'%s%s' % (nonce, body)).digest()
hmac_key = base64.b64decode(self.secret_key)
signature = hmac.new(hmac_key, message, hashlib.sha512).digest()
signature = base64.b64encode(signature)
request.headers.update({
'API-Key': self.api_key,
'API-Sign': signature
})
return request