Python-Anforderungen: POST-Anforderung löscht den Autorisierungsheader

9

Ich versuche, eine API-POST-Anforderung mithilfe der Python-Anforderungsbibliothek zu erstellen. Ich gehe durch einen AuthorizationHeader, aber wenn ich das Debuggen versuche, kann ich sehen, dass der Header gelöscht wird. Ich habe keine Ahnung, was los ist.

Hier ist mein Code:

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)

Wie Sie oben sehen können, habe ich den AuthorizationHeader in den Anforderungsargumenten manuell festgelegt , aber es fehlen die Header der tatsächlichen Anforderung : {'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+'}.

Eine zusätzliche Information ist, dass, wenn ich die POST-Anfrage in eine GET-Anfrage ändere, der AuthorizationHeader normal durchläuft!

Warum würde diese Bibliothek den Header für POST-Anfragen löschen und wie kann ich das zum Laufen bringen?

Verwenden von v2.4.3 der Anforderungen lib und Python 2.7.9

user4184113
quelle

Antworten:

9

TLDR

Die URL, die Sie anfordern, leitet POST-Anforderungen an einen anderen Host weiter, sodass die Anforderungsbibliothek den AuthoriztionHeader löscht, aus Angst, Ihre Anmeldeinformationen zu verlieren. Um dies zu beheben, können Sie die verantwortliche Methode in der SessionKlasse der Anforderungen überschreiben .

Einzelheiten

In Anforderungen 2.4.3 reqeuestswird der AuthorizationHeader nur entfernt, wenn eine Anforderung an einen anderen Host umgeleitet wird. Dies ist der relevante Code :

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

In neueren Versionen von requestswird der AuthorizationHeader in weiteren Fällen gelöscht (z. B. wenn die Umleitung von einem sicheren zu einem nicht sicheren Protokoll erfolgt).

Was in Ihrem Fall wahrscheinlich passiert, ist, dass Ihre POST-Anforderungen auf einen anderen Host umgeleitet werden. Die einzige Möglichkeit, die Authentifizierung für einen umgeleiteten Host mithilfe der Anforderungsbibliothek bereitzustellen, besteht in einer .netrcDatei. Leider können Sie damit nur HTTP Basic Auth verwenden, was Ihnen nicht viel hilft. In diesem Fall besteht die beste Lösung wahrscheinlich darin, requests.Sessiondieses Verhalten wie folgt zu klassifizieren und zu überschreiben:

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
quelle
1
Danke, das war das Problem!
user4184113
0

Dies ist, was Anforderungsdokumentation sagt:

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.

Werden Sie in Ihrer Anfrage umgeleitet?

Wenn dies der Fall ist, deaktivieren Sie die Umleitung mit dieser Option in der Post-Anfrage:

allow_redirects=False

Tarique
quelle
allow_redirects=Falseverhindert lediglich, dass Anforderungen der vom Server angeforderten Umleitung folgen. Dies hilft nicht, die Anfrage abzuschließen, sondern stoppt sie nur in der Mitte.
Kmaork
0

Das erste (und vielleicht das eigentliche) Problem, das ich sehe, ist das Erstellen, bearer_tokenda Sie nicht nur Ihr Token, sondern auch den Authentifizierungstyp codieren'Bearer'

Wie ich verstanden habe, müssen Sie nur das Token codieren und den leeren Authentifizierungstyp + das codierte Token in Ihrem Anforderungsheader angeben:

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

Wenn es sich (auch) um ein Umleitungsproblem handelt, können Sie einfach den richtigen Speicherort herausfinden und Ihre Anfrage an diese URL richten, oder Sie könnten darüber nachdenken, das Zugriffstoken innerhalb Ihres Körpers zu senden, POSTwenn der Server dies akzeptiert.

Odysseus
quelle
0

Aus der Dokumentation: 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.

Wenn Sie umgeleitet werden, können Sie versuchen, zu verwenden allow_redirects=false

yoshikage_kira
quelle
-1

Sie können versuchen, eine benutzerdefinierte Berechtigung in Headern zu verwenden.

Definieren Sie eine benutzerdefinierte Authentifizierungsklasse:

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

Verwenden Sie dies dann, um die Anfrage zu senden:

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)

Wenn dies funktioniert, akzeptieren Sie bitte die Antwort. Oder wenn Sie immer noch Probleme haben, lassen Sie es uns wissen. Hoffe das hilft.

Tarique
quelle
Es besteht keine Notwendigkeit, von zu erben requests.auth.AuthBase. Wenn Sie sich den Quellcode ansehen, werden Sie feststellen, dass er nur ausgelöst wird, NotImplementedwenn Sie vergessen, ihn zu überschreiben __call__.
Setzen Sie Monica
Dies ändert nichts an dem in der Frage beschriebenen Verhalten. Beim erneuten Erstellen der Authentifizierung bei einer Umleitung verwenden Anforderungen nicht das Auth-Argument.
Kmaork