首页 > 解决方案 > Coinbase API 标准 python 示例返回“无效签名”

问题描述

我正在尝试将 Coinbase API 与 Python 一起使用,从 Coinbase Developer API 页面上的标准示例开始:https ://developers.coinbase.com/docs/wallet/api-key-authentication#

这段代码只给了我错误,例如:

TypeError: key: expected bytes or bytearray, but got 'str'

经过一些谷歌搜索后,我做了一些调整,让我更进一步,但我仍然不在那里。API文档页面是否提供了一个过时的示例?

现在返回给我的主要信息是:{"id":"authentication_error","message":"invalid signature"}

我正在使用以下代码(用 xxxxxx 替换我的密钥):

import json, hmac, hashlib, time, requests
from requests.auth import AuthBase

# Before implementation, set environmental variables with the names API_KEY and API_SECRET
API_KEY = 'xxxxxxx'
API_SECRET = b'xxxxxxx'

def get_timestamp():
    return int(time.time() * 1000)


# Create custom authentication for Coinbase API
class CoinbaseWalletAuth(AuthBase):
    def __init__(self, api_key, secret_key):
        self.api_key = api_key
        self.secret_key = secret_key

    def __call__(self, request):
        timestamp = str(int(time.time()))

        print(timestamp)

        message = timestamp + request.method + request.path_url + (request.body or b'').decode()
        hmac_key = base64.b64decode(self.secret_key)
        signature = hmac.new(hmac_key, message.encode(), hashlib.sha256)
        signature_b64 = base64.b64encode(signature.digest()).decode()
        
        request.headers.update({
            'CB-ACCESS-SIGN': signature_b64,
            'CB-ACCESS-TIMESTAMP': timestamp,
            'CB-ACCESS-KEY': self.api_key,
            'Content-Type': 'application/json'
        })
        return request


api_url = 'https://api.coinbase.com/v2/'
auth = CoinbaseWalletAuth(API_KEY, API_SECRET)

# Get current user
r = requests.get(api_url + 'user', auth=auth)
print(r.json())
# {u'data': {u'username': None, u'resource': u'user', u'name': u'User'...

希望你能帮我解决这个问题。看起来这只是让基础知识正确......

标签: pythonapisignaturecoinbase-api

解决方案


首先要提到的是,您链接的页面中的代码是 python2,如果您使用它运行他们的代码,它可以立即运行。

我今天遇到了同样的问题,并意识到您的代码有多个问题(因为我假设您尝试了所有方法来修复它)所以我为您修复了这些问题,并且截至今天(21 年 4 月 28 日),python3 或 API 中的请求库) 有问题。我想出了一个解决办法。

import json, hmac, hashlib, time, requests
from requests.auth import AuthBase

# Before implementation, set environmental variables with the names API_KEY and API_SECRET
API_KEY = 'xxxxxxx'
API_SECRET = 'xxxxxxx'


# Create custom authentication for Coinbase API
class CoinbaseWalletAuth(AuthBase):
    def __init__(self, api_key, secret_key):
        self.api_key = api_key
        self.secret_key = secret_key

    def __call__(self, request):
        timestamp = str(int(time.time()))

        # the following try statement will fix the bug
        try:
            body = request.body.decode()
            if body == "{}":
                request.body = b""
                body = ''
         except AttributeError:
             request.body = b""
             body = ''

        message = timestamp + request.method + request.path_url + body
        signature = hmac.new(self.secret_key.encode(), message.encode(), hashlib.sha256).hexdigest()
        request.headers.update({
                'CB-ACCESS-SIGN': signature,
                'CB-ACCESS-TIMESTAMP': timestamp,
                'CB-ACCESS-KEY': self.api_key,
        })
        return request


api_url = 'https://api.coinbase.com/v2/'
auth = CoinbaseWalletAuth(API_KEY, API_SECRET)

# Get current user
r = requests.get(api_url + 'user', auth=auth)
print(r.json())
# {u'data': {u'username': None, u'resource': u'user', u'name': u'User'...

现在将其另存为test.py 并运行python3 test.py,假设您已在环境/系统中安装了库。

至于为什么有错误?
故障排除我发现request.bodyAPI 必须为空才能喜欢它(我的意思是空的''),因为它不希望该特定端点的主体。这是关于请求库的假设,当您将内容类型设置为 JSON 或json=在调用中使用时,它会看到您有一个空正文,它会自动使用{}. 这是有道理的,因为你不想通过说你要发送 json 但没有发送任何东西来欺骗服务器,所以 python3 中的请求对服务器来说很好。在 python2 中,请求库不会自动执行此操作。这对我们来说是一个问题,因为如果端点不接受主体,API 喜欢主体完全为空。

为什么这会修复它?
我不知道,因为这不是签名认证问题。我检查了工作 python2 版本和 python3 版本,并且签名相同,因此不是身份验证问题。看起来服务器不灵活,他们的请求正文是一个空的 JSON 对象。

因此,作为解决此问题的回顾,我们必须在看到请求主体设置为 时清除请求主体{}

TLDR:
服务器误导认为这是一个签名/身份验证问题,而实际上这是一个错误的请求。看看代码。


推荐阅读