Solicitações Python: solicitação POST descartando cabeçalho de Autorização


9

Estou tentando fazer uma solicitação de API POST usando a biblioteca de solicitações Python. Estou passando por um Authorizationcabeçalho, mas quando tento depurar, vejo que o cabeçalho está sendo descartado. Eu não tenho ideia do que está acontecendo.

Aqui está o meu 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 você pode ver acima, eu definir manualmente o Authorizationcabeçalho nos argumentos pedido, mas está faltando os cabeçalhos do pedido 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+'}.

Uma informação adicional é que, se eu alterar a solicitação POST para uma solicitação GET, o Authorizationcabeçalho passa normalmente!

Por que essa biblioteca descartaria o cabeçalho das solicitações POST e como faço para que isso funcione?

Usando a v2.4.3 das solicitações lib e Python 2.7.9

Respostas:


9

TLDR

O URL que você está solicitando redireciona solicitações POST para um host diferente, portanto a biblioteca de solicitações descarta o Authoriztioncabeçalho com medo de vazar suas credenciais. Para corrigir isso, você pode substituir o método responsável na Sessionclasse de solicitações .

Detalhes

Nas solicitações 2.4.3, o único local em que reqeuestso Authorizationcabeçalho é removido é quando uma solicitação é redirecionada para um host diferente. Este é o 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']

Nas versões mais recentes de requests, o Authorizationcabeçalho será descartado em casos adicionais (por exemplo, se o redirecionamento for de um protocolo seguro para um não seguro).

Portanto, o que provavelmente acontece no seu caso é que suas solicitações POST são redirecionadas para um host diferente. A única maneira de fornecer autenticação para um host redirecionado usando a biblioteca de solicitações é através de um .netrcarquivo. Infelizmente, isso só permitirá que você use HTTP Basic Auth, o que não ajuda muito. Nesse caso, a melhor solução é provavelmente subclassar requests.Sessione substituir esse comportamento, da seguinte maneira:

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)

11
Obrigado, este foi o problema!
user4184113 29/02

0

É isso que a documentação da solicitação diz:

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.

Você está sendo redirecionado em sua solicitação?

Se esse for o caso, tente desativar o redirecionamento com esta opção na solicitação de postagem:

allow_redirects=False


allow_redirects=Falseapenas impedirá que as solicitações sigam o redirecionamento solicitado pelo servidor. Isso não ajudará a concluir a solicitação, apenas a interromperá no meio.
kmaork 28/02

0

O primeiro (e talvez o real) problema que vejo é como você cria bearer_tokenporque não está codificando apenas seu token, mas também o tipo de autenticação'Bearer'

Pelo que entendi, você só precisa codificar o token e precisa fornecer o tipo de autenticação em branco + o token codificado no cabeçalho da sua solicitação:

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

Se for (também) um problema de redirecionamento, você pode simplesmente descobrir o local correto e fazer sua solicitação para esse URL ou pensar em enviar o token de acesso dentro do corpo do seu, POSTse o servidor estiver aceitando isso.


0

A partir da documentação: 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.

Se você estiver sendo redirecionado, tente usar allow_redirects=false


-1

você pode tentar usar uma autorização personalizada nos cabeçalhos.

Defina uma classe de autenticação 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

use isso para enviar a solicitação:

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)

Se isso funcionar, aceite a resposta. Ou se você ainda tiver problemas, informe-nos. Espero que isto ajude.


Não há necessidade de herdar requests.auth.AuthBase. Se você olhar para o código-fonte, verá que tudo o que faz é aumentar NotImplementedse você esquecer de substituir __call__.
Restabelecer Monica

Isso não mudará o comportamento descrito na pergunta. Ao recriar a autenticação em um redirecionamento, as solicitações não usam o argumento de autenticação.
kmaork 28/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.