Python-запросы: удаление POST-запроса. Заголовок авторизации.

9

Я пытаюсь сделать запрос 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

user4184113
источник

Ответы:

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 Basic 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)
kmaork
источник
1
Спасибо, это была проблема!
user4184113
0

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

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

Tarique
источник
allow_redirects=Falseбудет только препятствовать тому, чтобы запросы следовали за перенаправлением, запрошенным сервером. Это не поможет завершить запрос, просто остановит его посередине.
Kmaork
0

Первая (и, возможно, реальная) проблема, которую я вижу, заключается в том, как вы создаете, 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

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

yoshikage_kira
источник
-1

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

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

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)

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

Tarique
источник
Нет необходимости наследовать от requests.auth.AuthBase. Если вы посмотрите на исходный код для него, вы увидите, что все, что он делает, это поднять, NotImplementedесли вы забудете переопределить __call__.
Восстановить Монику
Это не изменит поведение, описанное в вопросе. При восстановлении аутентификации на перенаправлении запросы не используют аргумент аутентификации.
Kmaork