我在requests-python中使用自定义身份验证实现Coinbase's exchange API。以下代码适用于所有(经过身份验证的)基于GET的调用,但对于所有经过身份验证的基于POST的调用都失败(我没有尝试使用DELETE或UPDATE谓词)。我不明白为什么签名对两者都不起作用,因为GET的有效载荷为timestamp + method + path
,PUT的有效载荷为timestamp + method + path + body
,因此自定义auth似乎是正确的。添加正文并将GET更改为POST会出现问题。谢谢!
您可以在此处获取用于试用的API密钥:https://gdax.com/settings
import json, hmac, hashlib, time, requests, base64
from requests.auth import AuthBase
class CoinbaseAuth(AuthBase):
SIGNATURE_HTTP_HEADER = 'CB-ACCESS-SIGN'
TIMESTAMP_HTTP_HEADER = 'CB-ACCESS-TIMESTAMP'
KEY_HTTP_HEADER = 'CB-ACCESS-KEY'
PASSPHRASE_HTTP_HEADER = 'CB-ACCESS-PASSPHRASE'
def __init__(self, api_key, secret_key, passphrase):
self.api_key = api_key
self.secret_key = secret_key
self.passphrase = passphrase
def __call__(self, request):
#Add headers
request.headers[CoinbaseAuth.KEY_HTTP_HEADER] = self.api_key
request.headers[CoinbaseAuth.PASSPHRASE_HTTP_HEADER] = self.passphrase
timestamp = str(time.time())
request.headers[CoinbaseAuth.TIMESTAMP_HTTP_HEADER] = timestamp
#add signature
method = request.method
path = request.path_url
content = request.body
message = timestamp + method + path
if content:
message += content
hmac_key = base64.b64decode(self.secret_key)
sig = hmac.new(hmac_key, message, hashlib.sha256)
sig_b64 = sig.digest().encode("base64").rstrip("\n")
#Add signature header
request.headers[CoinbaseAuth.SIGNATURE_HTTP_HEADER] = sig_b64
return request
#Get your keys here: https://gdax.com/settings
key = 'KEY GOES HERE'
secret = 'SECRET GOES HERE'
passphrase = 'PASSPHRASE GOES HERE'
api_url = 'https://api.gdax.com:443/'
auth = CoinbaseAuth(API_KEY, API_SECRET, API_PASS)
#GETs work, shows account balances
r = requests.get(api_url + 'accounts', auth=auth)
print r.json()
#POSTs fail: {message: 'invalid signature'}
order = {}
order['size'] = 0.01
order['price'] = 100
order['side'] = 'buy'
order['product_id'] = 'BTC-USD'
r = requests.post(api_url + 'orders', data=json.dumps(order), auth=auth)
print r.json()
输出:
GET电话:200: [{u'available': .......}]
POST电话:400: {u'message': u'invalid signature'}
request.post(..., data='',...)
---服务器会对{u'message': u'Missing product_id'}
做出适当的响应。
答案 0 :(得分:3)
我不知道为什么,但如果我将data
关键字参数更改为requests.post()
到json
则可行:
r = requests.post(api_url + 'orders', json=order, auth=auth)
编辑:唯一改变的是AFAICT,标题中的内容类型从文本更改为JSON。所以很可能是unicode vs ASCII编码问题。以下是最近添加此功能的库的问题:https://github.com/kennethreitz/requests/issues/2025#issuecomment-46337236
答案 1 :(得分:0)
我认为内容需要是一个没有空格的json字符串(这就是节点示例所做的事情)。也许试试这个:
message += json.dumps(content).replace(' ', '')
答案 2 :(得分:0)
在查看nodeJS的公共gdax API之前,我遇到了同样的问题,并发现他们正在使用GDAX API文档中未提及的一些其他标头。我添加了它们然后开始工作了。请参阅我对以下内容的回答:GDAX API Always Returns Http 400 "Invalid Signature" Even though I do it exactly like in the API Doc