Permintaan Python: Permintaan POST menjatuhkan header Otorisasi

9

Saya mencoba membuat permintaan POST API menggunakan pustaka permintaan Python. Saya melewati Authorizationheader tetapi ketika saya mencoba debugging, saya bisa melihat bahwa header sedang dijatuhkan. Saya tidak tahu apa yang sedang terjadi.

Ini kode saya:

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)

Seperti yang Anda lihat di atas, saya secara manual mengatur Authorizationheader argumen permintaan, tapi itu hilang header permintaan yang sebenarnya itu: {'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+'}.

Sepotong informasi tambahan adalah bahwa jika saya mengubah permintaan POST menjadi permintaan GET, Authorizationheader akan melewati secara normal!

Mengapa pustaka ini menjatuhkan header untuk permintaan POST dan bagaimana cara membuatnya agar berfungsi?

Menggunakan v2.4.3 dari permintaan lib dan Python 2.7.9

pengguna4184113
sumber

Jawaban:

9

TLDR

URL yang Anda minta akan mengalihkan permintaan POST ke host yang berbeda, sehingga pustaka permintaan menjatuhkan Authoriztionheader karena takut bocor kredensial Anda. Untuk memperbaikinya, Anda dapat mengganti metode yang bertanggung jawab di Sessionkelas permintaan .

Detail

Dalam permintaan 2.4.3, satu-satunya tempat di mana reqeuestsmenghapus Authorizationheader adalah ketika permintaan dialihkan ke host yang berbeda. Ini adalah kode yang relevan :

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

Dalam versi yang lebih baru requests, Authorizationtajuk akan dijatuhkan dalam kasus tambahan (misalnya jika pengalihan dari protokol aman ke non-aman).

Jadi apa yang mungkin terjadi dalam kasus Anda, adalah bahwa permintaan POST Anda dialihkan ke host yang berbeda. Satu-satunya cara Anda dapat memberikan otentikasi untuk host yang diarahkan menggunakan perpustakaan permintaan, adalah melalui .netrcfile. Sayangnya itu hanya akan memungkinkan Anda untuk menggunakan HTTP Basic Auth, yang tidak banyak membantu Anda. Dalam hal ini, solusi terbaik mungkin untuk mensubclass requests.Sessiondan menimpa perilaku ini, seperti:

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
sumber
1
Terima kasih, ini masalahnya!
user4184113
0

Inilah yang dikatakan dokumentasi permintaan:

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.

Apakah Anda dialihkan ke permintaan Anda?

Jika demikian, coba nonaktifkan pengalihan dengan opsi ini dalam permintaan posting:

allow_redirects=False

Tarique
sumber
allow_redirects=Falsehanya akan mencegah permintaan mengikuti pengalihan yang diminta oleh server. Ini tidak akan membantu menyelesaikan permintaan, itu hanya akan menghentikannya di tengah.
kmaork
0

Masalah pertama (dan mungkin yang sebenarnya) yang saya lihat adalah bagaimana Anda membuat bearer_tokenkarena Anda tidak hanya mengkodekan token Anda, tetapi juga jenis otentikasi'Bearer'

Seperti yang saya pahami, Anda hanya perlu menyandikan token dan harus memberikan jenis autentikasi kosong + token yang disandikan dalam tajuk permintaan Anda:

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

Jika ini (juga) merupakan masalah pengalihan, Anda bisa mengetahui lokasi yang benar dan mengajukan permintaan Anda ke url ini atau Anda mungkin berpikir untuk mengirim token akses ke dalam tubuh Anda POSTjika server menerima ini.

Odiseus
sumber
0

Dari dokumentasi: 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.

Jika Anda diarahkan, Anda dapat mencoba menggunakan allow_redirects=false

yoshikage_kira
sumber
-1

Anda dapat mencoba menggunakan otorisasi khusus dalam tajuk.

Tentukan kelas otentikasi khusus:

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

kemudian gunakan ini untuk mengirim permintaan:

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)

Jika ini berhasil tolong terima jawabannya. Atau jika Anda masih memiliki masalah, beri tahu kami. Semoga ini membantu.

Tarique
sumber
Tidak perlu mewarisi dari requests.auth.AuthBase. Jika Anda melihat kode sumber untuk itu, Anda akan melihat bahwa yang dilakukannya hanyalah menaikkan NotImplementedjika Anda lupa menimpanya __call__.
Pasang kembali Monica
Ini tidak akan mengubah perilaku yang dijelaskan dalam pertanyaan. Saat membangun kembali auth pada pengalihan, permintaan tidak menggunakan argumen auth.
kmaork