Python请求:POST请求丢弃Authorization头



我正在尝试使用Python请求库生成一个API POST请求。我正在通过一个Authorization标头,但当我尝试调试时,我可以看到该标头正在被丢弃。我不知道发生了什么事。

这是我的代码:

access_token = get_access_token()
bearer_token = base64.b64encode(bytes("'Bearer {}'".format(access_token)), 'utf-8')
headers = {'Content-Type': 'application/json', 'Authorization': bearer_token}
data = '{"FirstName" : "Jane", "LastName" : "Smith"}'
response = requests.post('https://myserver.com/endpoint', headers=headers, data=data)

正如您在上面看到的,我在请求参数中手动设置了Authorization标头,但它缺少实际请求的标头:{'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.4.3 CPython/2.7.9 Linux/4.1.19-v7+'}

另外一条信息是,如果我将POST请求更改为GET请求,则Authorization标头将正常通过!

为什么这个库会丢弃POST请求的头,以及如何使其工作?

使用请求库的v2.4.3和Python 2.7.9

TLDR

您请求的url会将POST请求重定向到另一个主机,因此请求库会删除Authoriztion标头,以免泄露您的凭据。要修复此问题,可以覆盖请求的Session类中的责任方法。

详细信息

在请求2.4.3中,reqeuests删除Authorization标头的唯一位置是将请求重定向到其他主机时。这是相关代码:

if 'Authorization' in headers:
# If we get redirected to a new host, we should strip out any
# authentication headers.
original_parsed = urlparse(response.request.url)
redirect_parsed = urlparse(url)
if (original_parsed.hostname != redirect_parsed.hostname):
del headers['Authorization']

requests的较新版本中,在其他情况下(例如,如果重定向是从安全协议到非安全协议(,Authorization标头将被丢弃。

因此,在您的情况下可能发生的情况是,您的POST请求被重定向到不同的主机。使用请求库为重定向主机提供身份验证的唯一方法是通过.netrc文件。遗憾的是,这只会允许您使用HTTP基本身份验证,这对您没有多大帮助。在这种情况下,最好的解决方案可能是将requests.Session子类化并覆盖此行为,如下所示:

from requests import Session
class NoRebuildAuthSession(Session):
def rebuild_auth(self, prepared_request, response):
"""
No code here means requests will always preserve the Authorization
header when redirected.
Be careful not to leak your credentials to untrusted hosts!
"""
session = NoRebuildAuthSession()
response = session.post('https://myserver.com/endpoint', headers=headers, data=data)

编辑

我在github上打开了一个请求库的pull请求,以便在发生这种情况时添加警告。它一直在等待第二次合并批准(已经三个月了(。

这就是请求文档所说的:

Authorization headers set with headers= will be overridden if credentials are specified in .netrc, which in turn will be overridden by the auth= parameter. Authorization headers will be removed if you get redirected off-host.

您的请求是否被重定向?

如果是这种情况,请尝试在后请求中使用此选项禁用重定向:

allow_redirects=False

我看到的第一个(可能也是实际的(问题是如何创建bearer_token,因为您不仅要对令牌进行编码,还要对身份验证类型'Bearer'进行编码

据我所知,您只需要对令牌进行编码,并且必须在您的请求标头中提供空白身份验证类型+编码的令牌:

bearer_token = str(base64.b64encode(access_token.encode()), "utf8")
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(bearer_token)}

如果(也是(重定向问题,您可以简单地找到正确的位置并向该url发出请求,或者如果服务器接受,您可以考虑在POST的主体中发送访问令牌。

来自文档:Requests will attempt to get the authentication credentials for the URL’s hostname from the user’s netrc file. The netrc file overrides raw HTTP authentication headers set with headers=. If credentials for the hostname are found, the request is sent with HTTP Basic Auth.

如果你被重定向,你可以尝试使用allow_redirects=false

循环请求对我有效

response = do_request(url, access_tok, "GET", payload={}, headers={}, allow_redirect=False)
if response.status_code in range(300, 310):
new_response = do_request(response.headers['Location'], access_tok, "GET", payload={}, headers={},)
# print(new_response.status_code)
pprint(new_response.json())

我的问题是.netrc中有一个覆盖Authorization标头的条目。其他答案提到了.netrc,但没有提及它。解决方案是手动创建一个Session并将trust_env设置为False。

import requests
session = requests.Session()
session.trust_env = False
headers={'Authorization': f'Bearer {TOKEN}'}
session.post(url, headers=headers)

GitHub存在问题,无法阻止此覆盖。

您可以尝试在标头中使用自定义授权。

定义自定义身份验证类:

class MyAuth(requests.auth.AuthBase):
def __init__(self, bearer_token):
self.username = None
self.bearer_token = bearer_token
def __call__(self, r):
r.headers['Authorization'] = self.bearer_token
return r

然后使用它发送请求:

headers = {'Content-Type': 'application/json'}
data = '{"FirstName" : "Jane", "LastName" : "Smith"}'
response = requests.post('https://myserver.com/endpoint', headers=headers, auth=MyAuth(bearer_token), data=data)

如果有效,请接受答案。或者,如果您仍然有问题,请告诉我们。希望这能有所帮助。

使用"request"lib在POST请求中发送Authorization标头。在Python中简单地使用这个:

requests.post('https://api.github.com/user', auth=('user', 'pass'))

这是一个基本的身份验证。

相关内容

  • 没有找到相关文章

最新更新