Python запросов: удаление POST-запросов. Заголовок авторизации. - PullRequest
9 голосов
/ 23 февраля 2020

Я пытаюсь сделать запрос API POST, используя библиотеку запросов Python. Я передаю заголовок 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 lib запросов и Python 2.7.9

Ответы [ 5 ]

9 голосов
/ 28 февраля 2020

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 Basi c Auth, который вам мало поможет. В этом случае лучшее решение, вероятно, состоит в том, чтобы создать подкласс 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)
0 голосов
/ 02 марта 2020

Из документации: 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

0 голосов
/ 28 февраля 2020

Первая (и, возможно, реальная) проблема, которую я вижу, заключается в том, как вы создаете bearer_token, потому что вы кодируете не только свой токен, но и тип аутентификации 'Bearer'

Как я понял, вам нужно только закодируйте токен и укажите пустой тип аутентификации + закодированный токен в заголовке вашего запроса:

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

Если это (также) проблема с перенаправлением, вы можете просто узнать правильное местоположение и сделать запрос на этот URL, или вы можете подумать об отправке токена доступа в теле вашего POST, если сервер принимает это.

0 голосов
/ 25 февраля 2020

вы можете попробовать использовать пользовательскую авторизацию в заголовках.

Определите пользовательский класс аутентификации:

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)

Если это работает, примите ответ. Или, если у вас все еще есть проблема, сообщите нам. Надеюсь, это поможет.

0 голосов
/ 23 февраля 2020

Это то, о чем говорится в документации запроса:

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

...