Demandes Python: demande POST supprimant l'en-tête d'autorisation

9

J'essaye de faire une requête API POST en utilisant la bibliothèque de requêtes Python. Je passe par un en- Authorizationtête, mais lorsque j'essaie de déboguer, je peux voir que l'en-tête est supprimé. Je ne ai aucune idée de ce qui se passe.

Voici mon 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)

Comme vous pouvez le voir ci - dessus, régler manuellement l' en- Authorizationtête dans les arguments de requête, mais il manque les en- têtes de la demande réelle: {'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+'}.

Une information supplémentaire est que si je change la demande POST en demande GET, l'en- Authorizationtête passe normalement!

Pourquoi cette bibliothèque supprimerait-elle l'en-tête des requêtes POST et comment puis-je faire en sorte que cela fonctionne?

Utilisation de la version 2.4.3 de la bibliothèque de demandes et de Python 2.7.9

user4184113
la source

Réponses:

9

TLDR

L'URL que vous demandez redirige les demandes POST vers un autre hôte, de sorte que la bibliothèque de demandes supprime le Authoriztion tête de peur de divulguer vos informations d'identification. Pour résoudre ce problème, vous pouvez remplacer la méthode responsable dans la Sessionclasse des demandes .

Détails

Dans les demandes 2.4.3, le seul endroit où reqeuestssupprime l'en- Authorizationtête est lorsqu'une demande est redirigée vers un hôte différent. Voici le code pertinent :

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

Dans les versions plus récentes de requests,Authorization tête sera supprimé dans des cas supplémentaires (par exemple si la redirection est d'un protocole sécurisé vers un protocole non sécurisé).

Donc, ce qui se passe probablement dans votre cas, c'est que vos demandes POST sont redirigées vers un hôte différent. La seule façon de fournir une authentification à un hôte redirigé à l'aide de la bibliothèque de demandes est via un .netrcfichier. Malheureusement, cela ne vous permettra d'utiliser que l'authentification HTTP de base, ce qui ne vous aide pas beaucoup. Dans ce cas, la meilleure solution est probablement de sous requests.Session-classer et de remplacer ce comportement, comme ceci:

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
la source
1
Merci, c'était le problème!
user4184113
0

Voici ce que dit la documentation de la demande:

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.

Êtes-vous redirigé dans votre demande?

Si tel est le cas, essayez de désactiver la redirection avec cette option dans la demande de publication:

allow_redirects=False

Tarique
la source
allow_redirects=Falseempêchera simplement les demandes de suivre la redirection demandée par le serveur. Cela n'aidera pas à terminer la demande, cela l'arrêtera simplement au milieu.
kmaork
0

Le premier (et peut-être le vrai) problème que je vois est de savoir comment créer bearer_token car vous n'encodez pas seulement votre jeton mais aussi le type d'authentification'Bearer'

Si j'ai bien compris, il vous suffit de coder le jeton et de fournir le type d'authentification vierge + le jeton codé dans l'en-tête de votre demande:

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

S'il s'agit (également) d'un problème de redirection, vous pouvez simplement trouver l'emplacement correct et faire votre demande à cette URL ou vous pourriez penser à envoyer le jeton d'accès dans le corps de votre POSTsi le serveur l'accepte.

Ulysse
la source
0

De la documentation: 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.

Si vous êtes redirigé, vous pouvez essayer d'utiliser allow_redirects=false

yoshikage_kira
la source
-1

vous pouvez essayer d'utiliser une autorisation personnalisée dans les en-têtes.

Définissez une classe d'authentification personnalisée:

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

puis utilisez ceci pour envoyer la demande:

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)

Si cela fonctionne, veuillez accepter la réponse. Ou si vous avez toujours un problème, faites-le nous savoir. J'espère que cela t'aides.

Tarique
la source
Il n'est pas nécessaire d'hériter requests.auth.AuthBase. Si vous regardez le code source pour cela, vous verrez que tout ce qu'il fait, c'est augmenter NotImplementedsi vous oubliez de remplacer __call__.
Rétablir Monica le
Cela ne changera pas le comportement décrit dans la question. Lors de la reconstruction de l'auth sur une redirection, les requêtes n'utilisent pas l'argument auth.
kmaork