Solicitudes de Python: solicitud POST que descarta el encabezado de autorización

9

Estoy tratando de hacer una solicitud API POST usando la biblioteca de solicitudes Python. Estoy pasando por un Authorizationencabezado pero cuando intento depurar, puedo ver que el encabezado se está cayendo. No tengo idea de lo que está pasando.

Aquí está mi código:

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)

Como se puede ver arriba, me puse manualmente el Authorizationencabezado en los argumentos de la petición, pero no se encuentra cabeceras de la solicitud real: {'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+'}.

Una información adicional es que si cambio la solicitud POST a una solicitud GET, ¡el Authorizationencabezado pasa normalmente!

¿Por qué esta biblioteca dejaría caer el encabezado para las solicitudes POST y cómo puedo hacer que esto funcione?

Usando v2.4.3 de las solicitudes lib y Python 2.7.9

usuario4184113
fuente

Respuestas:

9

TLDR

La url que solicita redirige las solicitudes POST a un host diferente, por lo que la biblioteca de solicitudes descarta el Authoriztionencabezado por temor a que se filtren sus credenciales. Para solucionarlo, puede anular el método responsable en la Sessionclase de solicitudes .

Detalles

En las solicitudes 2.4.3, el único lugar donde reqeuestselimina el Authorizationencabezado es cuando una solicitud se redirige a un host diferente. Este es el código relevante :

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

En las versiones más recientes de requests, el Authorizationencabezado se eliminará en casos adicionales (por ejemplo, si la redirección es de un protocolo seguro a uno no seguro).

Entonces, lo que probablemente sucede en su caso, es que sus solicitudes POST se redirigen a un host diferente. La única forma en que puede proporcionar autenticación para un host redirigido utilizando la biblioteca de solicitudes es a través de un .netrcarchivo. Lamentablemente, eso solo le permitirá usar HTTP Basic Auth, lo que no le ayuda mucho. En ese caso, la mejor solución es probablemente subclasificar requests.Sessiony anular este comportamiento, así:

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
fuente
1
Gracias, este fue el problema!
user4184113
0

Esto es lo que dice la documentación de la solicitud:

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.

¿Estás siendo redirigido en tu solicitud?

Si este es el caso, intente desactivar la redirección con esta opción en la solicitud posterior:

allow_redirects=False

Tarique
fuente
allow_redirects=Falsesolo evitará que las solicitudes sigan la redirección solicitada por el servidor. Esto no ayudará a completar la solicitud, solo la detendrá en el medio.
kmaork
0

El primer problema (y tal vez el real) que veo es cómo crea bearer_tokenporque no está codificando solo su token sino también el tipo de autenticación'Bearer'

Como entendí, solo necesita codificar el token y debe proporcionar el tipo de autenticación en blanco + el token codificado dentro del encabezado de su solicitud:

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

Si es (también) un problema de redireccionamiento, simplemente puede encontrar la ubicación correcta y hacer su solicitud a esta url o puede pensar en enviar el token de acceso dentro del cuerpo de su POSTsi el servidor lo acepta.

Odiseo
fuente
0

De la documentación: 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 está siendo redirigido, puede intentar usar allow_redirects=false

yoshikage_kira
fuente
-1

puede intentar usar una autorización personalizada en los encabezados.

Defina una clase de autenticación personalizada:

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

luego use esto para enviar la solicitud:

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 esto funciona, por favor acepte la respuesta. O si aún tiene problemas, infórmenos. Espero que esto ayude.

Tarique
fuente
No hay necesidad de heredar de requests.auth.AuthBase. Si observa el código fuente, verá que todo lo que hace es aumentar NotImplementedsi olvida anular __call__.
Restablece a Monica
Esto no cambiará el comportamiento descrito en la pregunta. Al reconstruir la autenticación en una redirección, las solicitudes no usan el argumento de autenticación.
kmaork