首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Auth对象的requests.Request方法中签名__call__的主体?

如何在Auth对象的requests.Request方法中签名__call__的主体?
EN

Stack Overflow用户
提问于 2018-10-08 15:05:53
回答 1查看 1.8K关注 0票数 1

我想给克拉肯写个好帮手。我希望它尽可能自动,所以它需要:

  1. 在POST正文中添加一个nonce (time.time()*1000)
  2. 计算邮件正文上的签名
  3. 将签名放入标头中

我根据的答案编写了明显的代码:

代码语言:javascript
复制
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                                         

我调用它们(从另一个对象的包装器方法)如下:

代码语言:javascript
复制
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)                                                                                             

...but,它不起作用。注释掉的print()语句显示它得到的是PreparedRequest对象而不是Request对象,因此对request.prepare()的调用是对PreparedRequest.prepare no 没有用的调用,因为没有request.data,因为它已经被转换为body属性。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-08 15:32:21

您无法访问请求的data属性,因为身份验证对象应用于没有.data属性的实例

打电话 (所有request.<method>session.<method>调用都使用)的正常流如下所示:

  • 创建Request()实例时使用与原始调用相同的参数。
  • 请求被传递给Session.prepare_request(),后者首先将会话存储的基值与原始调用的参数合并,然后再合并。
  • 创建了一个实例
  • 在准备好的请求实例上调用方法,传递来自Request实例和会话的合并数据。
  • prepare()方法调用各种self.prepare_*方法,包括PreparedRequest.prepare_auth()
  • PreparedRequest.prepare_auth()调用auth(self)使身份验证对象有机会将信息附加到请求。

不幸的是,在此流程中,除了PreparedRequest.prepare()PreparedRequest.prepare_body()之外,任何其他人都不能使用原始的PreparedRequest.prepare()映射,而在这些方法中,映射是一个局部变量。您不能从身份验证对象访问它。

你的选择是:

  • 再次解码主体,并使用更新的映射调用prepare_body()
  • 不使用身份验证对象,而是使用来自我的答案的另一条路径;显式地创建一个准备好的请求并首先操作data
  • 使用Python堆栈进行愉快的地狱操作,并从prepare()方法中提取本地值,这是两个帧的结果。我真的不能推荐这条路。

为了更好地封装身份验证方法,我将继续解码/重新编码;后者通过重用PreparedRequest.prepare_body()就足够简单了。

代码语言:javascript
复制
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
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52705158

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档