Żądania w języku Python: usuwanie żądania POST Nagłówek autoryzacji

9

Próbuję złożyć żądanie POST API przy użyciu biblioteki żądań Python. Przechodzę przez Authorizationnagłówek, ale kiedy próbuję debugować, widzę, że nagłówek jest upuszczany. Nie mam pojęcia, co się dzieje.

Oto mój kod:

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)

Jak widać powyżej, ręcznie ustawić Authorizationnagłówek w argumentach żądanie, ale brakuje nagłówków aktualnie prośbą za: {'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+'}.

Dodatkową informacją jest to, że jeśli zmienię żądanie POST na żądanie GET, Authorizationnagłówek przechodzi normalnie!

Dlaczego ta biblioteka upuszcza nagłówek żądań POST i jak mogę to uruchomić?

Korzystanie z wersji 2.2.3 żądań lib i Python 2.7.9

użytkownik4184113
źródło

Odpowiedzi:

10

TLDR

Żądany adres URL przekierowuje żądania POST do innego hosta, więc biblioteka żądań upuszcza Authoriztionnagłówek w obawie przed wyciekiem poświadczeń. Aby to naprawić, możesz zastąpić metodę odpowiedzialną w Sessionklasie żądań .

Detale

W żądaniach 2.4.3 jedynym miejscem, w którym reqeuestsusuwa się Authorizationnagłówek, jest przekierowanie żądania do innego hosta. To jest odpowiedni kod :

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']

W nowszych wersjach requestsThe Authorizationnagłówek zostanie usunięty w dodatkowych przypadków (na przykład, jeśli przekierowanie jest z bezpiecznego do niezabezpieczonego protokołu).

Więc prawdopodobnie dzieje się w twoim przypadku, że twoje żądania POST są przekierowywane do innego hosta. Jedynym sposobem na zapewnienie uwierzytelnienia przekierowanego hosta za pomocą biblioteki żądań jest użycie .netrcpliku. Niestety, pozwoli to tylko na użycie podstawowego uwierzytelniania HTTP, co niewiele pomoże. W takim przypadku najlepszym rozwiązaniem jest prawdopodobnie podklasę requests.Sessioni zastąpienie tego zachowania, na przykład:

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)

Edytować

Otworzyłem żądanie ściągnięcia do biblioteki żądań na github, aby dodać ostrzeżenie, gdy to nastąpi. Czeka na połączenie drugiej zgody (już trzy miesiące).

kmaork
źródło
1
Dzięki, to był problem!
user4184113
0

Tak mówi dokumentacja wniosku:

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.

Czy otrzymujesz przekierowanie w swoim żądaniu?

W takim przypadku spróbuj wyłączyć przekierowanie za pomocą tej opcji w żądaniu postu:

allow_redirects=False

Tarique
źródło
allow_redirects=Falsepo prostu zapobiegnie przesyłaniu żądań przez przekierowanie żądane przez serwer. To nie pomoże w wypełnieniu wniosku, po prostu zatrzyma go w środku.
kmaork
0

Pierwszym (i być może faktycznym) problemem, jaki widzę, jest sposób tworzenia, bearer_tokenponieważ nie kodujesz tylko tokena, ale także typ uwierzytelnienia'Bearer'

Jak zrozumiałem, musisz tylko zakodować token i podać pusty typ uwierzytelnienia + zakodowany token w nagłówku żądania:

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

Jeśli jest to (także) problem z przekierowaniem, możesz po prostu znaleźć prawidłową lokalizację i złożyć wniosek na ten adres URL lub możesz pomyśleć o wysłaniu tokena dostępu w ciele, POSTjeśli serwer to akceptuje.

Odyseusz
źródło
0

Z dokumentacji: 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.

Jeśli zostaniesz przekierowany, możesz spróbować użyć allow_redirects=false

yoshikage_kira
źródło
-1

możesz spróbować użyć niestandardowej autoryzacji w nagłówkach.

Zdefiniuj niestandardową klasę uwierzytelniania:

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

następnie użyj tego, aby wysłać zapytanie:

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)

Jeśli to zadziała, zaakceptuj odpowiedź. Lub jeśli nadal masz problem, daj nam znać. Mam nadzieję że to pomoże.

Tarique
źródło
Nie ma potrzeby dziedziczenia requests.auth.AuthBase. Jeśli spojrzysz na jego kod źródłowy, zobaczysz, że wszystko, co robi, to podnoszenie, NotImplementedjeśli zapomnisz przesłonić __call__.
Przywróć Monikę
Nie zmieni to zachowania opisanego w pytaniu. Podczas przebudowywania autoryzacji na przekierowaniu żądania nie używają argumentu autoryzacji.
kmaork