使用自定义认证修改请求参数

6 投票
1 回答
2376 浏览
提问于 2025-04-18 08:07

我刚把我的请求库升级到了2.3.0(之前是0.14.0),结果我的自定义认证功能不再正常工作了。问题在于,我们的自定义认证会在请求中添加一个API密钥和一个时间戳,这样我们所有的辅助方法就不用每次都加这些东西。

class APIAuth(requests.auth.AuthBase):
    def __call__(self, request):
        api_secret = settings.API_SHARED_SECRET
        api_key = settings.API_KEY
        request.params.update(dict(
            api_key=api_key,
            timestamp=int(time.time()*1000)))
        signature = base64.b64encode(hmac.new(
            api_secret,
            msg=unquote(request.full_url),
            digestmod=hashlib.sha256
            ).digest()).decode()
        request.headers['Authorization'] = "signature {0}".format(signature)
        return request

出现的错误是:

AttributeError: 'PreparedRequest' object has no attribute 'params'

准备好的请求不允许修改参数字典,可能是因为它已经构建完成了。有没有简单的方法可以从我们的自定义认证中更新参数字典,同时保留现有的参数不变?还是说我必须忍痛割爱,每个请求方法都得手动加这两个参数?

1 个回答

7

没错,现在传入的是一个 PreparedRequest,而且URL的查询字符串已经根据参数设置好了。

不过,PreparedRequest.prepare_url() 方法可以让你 更新 URL,添加更多的参数:

class APIAuth(requests.auth.AuthBase):
    def __call__(self, request):
        api_secret = settings.API_SHARED_SECRET
        api_key = settings.API_KEY
        request.prepare_url(request.url, dict(
            api_key=api_key,
            timestamp=int(time.time()*1000)))
        signature = base64.b64encode(hmac.new(
            api_secret,
            msg=unquote(request.full_url),
            digestmod=hashlib.sha256
            ).digest()).decode()
        request.headers['Authorization'] = "signature {0}".format(signature)
        return request

示例:

>>> import requests
>>> prepared = requests.Request(url='http://httpbin.org/get').prepare()
>>> prepared.url
'http://httpbin.org/get'
>>> prepared.prepare_url(prepared.url, {'foo': 'bar', 'spam': 42})
>>> prepared.url
'http://httpbin.org/get?foo=bar&spam=42'
>>> prepared.prepare_url(prepared.url, {'monty': 'python'})
>>> prepared.url
'http://httpbin.org/get?foo=bar&spam=42&monty=python'

通过传入 prepared.url,URL会被更新,添加额外的参数。新的参数总是 附加 的;如果新参数和已经添加的参数名字相同,旧的参数不会被删除。

撰写回答