Permintaan Flask-Login POST berubah menjadi permintaan GET setelah login [duplikat]

Saya menggunakan flask-login untuk menangani autentikasi aplikasi saya, yang merupakan API yang mengharapkan header Otorisasi Dasar HTTP sebagai bagian dari setiap permintaan (sehingga pengguna dapat login dan membuat permintaan tanpa mengkhawatirkan sesi, cookie, atau keharusan melakukan login dan permintaan dalam langkah terpisah).

Permintaan saya berjalan seperti ini:

POST /api/group/48
GET /login?next=%2Fapi%2Fgroup%2F48
GET /api/group/48 

Artinya, permintaan POST ke /api/group/48 dicegat dan dialihkan ke titik akhir /login (seperti yang diharapkan). Apa yang terjadi di /login tidak interaktif - dibutuhkan header Otorisasi Dasar dan memasukkan pengguna.

Setelah login selesai, klien dialihkan kembali ke /api/group/48 - namun kali ini sebagai permintaan GET, bukan POST. Dan di aplikasi ini, titik akhir /api/group/48 hanya mengharapkan data POST, sehingga mati dengan kesalahan 405 (Metode tidak diizinkan).

Apakah ini perilaku yang diharapkan dari login labu? Bagaimana saya bisa melewati permintaan POST seperti yang dikirimkan semula? (atau sebagai alternatif, haruskah saya menggunakan arsitektur yang berbeda sehingga pengalihan ke /login, lalu kembali ke /api/group/48 tidak terjadi dan data POST tidak hilang?)

Saya belum menyertakan kode, karena menurut saya ini bukan masalah khusus kode. Namun jika ternyata saya melakukan kesalahan, saya dapat memposting beberapa contoh kode.

Terima kasih kepada siapa pun yang dapat membantu.


person David White    schedule 13.07.2016    source sumber
comment
Akan sulit untuk mencoba menjawab pertanyaan Anda tanpa kode contoh apa pun. Bisakah Anda memasukkan contoh minimal (dapat dijalankan jika memungkinkan) dari masalahnya?   -  person Quint    schedule 13.07.2016
comment
Saya tidak percaya bahwa protokol HTTP mengizinkan pengalihan seperti itu. Setelah login autentikasi dasar selesai, menurut saya permintaan berikutnya dalam siklus ini adalah permintaan GET.   -  person Wayne Werner    schedule 13.07.2016


Jawaban (2)


Ini lebih dari sekadar pengalihan (yang mungkin masih menjadi masalah bagi beberapa browser/klien). Klien Anda perlu mengingat isi permintaan awal, dan mempostingnya kembali nanti. Tidak ada mekanisme seperti itu dalam spesifikasi HTTP.

Yang dapat Anda lakukan adalah mengingat permintaan tersebut (dalam sesi serupa), lalu melakukan pengalihan, lalu memproses permintaan yang disimpan. Saya rasa tidak ada jalan pintas di sini.

person frnhr    schedule 13.07.2016

Jika Anda benar-benar perlu mengalihkan sebagai POST, Anda dapat melakukan ini. Misalkan Anda memiliki tampilan dengan pengalihan seperti ini (diambil tanpa malu-malu dari dokumen flask-login):

@app.route('/login', methods=['GET', 'POST'])
def login():
    # Here we use a class of some kind to represent and validate our
    # client-side form data. For example, WTForms is a library that will
    # handle this for us, and we use a custom LoginForm to validate.
    form = LoginForm()
    if form.validate_on_submit():
        # Login and validate the user.
        # user should be an instance of your `User` class
        login_user(user)

        flask.flash('Logged in successfully.')

        next = flask.request.args.get('next')
        # next_is_valid should check if the user has valid
        # permission to access the `next` url
        if not next_is_valid(next):
            return flask.abort(400)

        return flask.redirect(next or flask.url_for('index'))
    return flask.render_template('login.html', form=form)

Kemudian jawaban ini mengutip Wikipedia:

Banyak browser web menerapkan kode ini dengan cara yang melanggar standar ini, mengubah jenis permintaan dari permintaan baru menjadi GET, terlepas dari jenis yang digunakan dalam permintaan asli (misalnya POST). 1 Karena alasan ini, HTTP/1.1 (RFC 2616) menambahkan kode status baru 303 dan 307 untuk membedakan kedua perilaku tersebut , dengan 303 mengamanatkan perubahan jenis permintaan menjadi GET, dan 307 mempertahankan jenis permintaan seperti yang dikirimkan semula.

Jadi jawaban Anda adalah mengubah pengalihan ke flask.redirect(next or flask.url_for('index'), code=307)

Perhatikan juga bahwa Anda mungkin perlu mengalihkan ke login tampilan sebagai POST juga agar dapat berfungsi. Anda dapat membuat penangan tidak sah khusus Anda:

@login_manager.unauthorized_handler
def unauthorized():
    # do stuff
    return a_response
person valignatev    schedule 13.07.2016
comment
Itu ide yang menarik, valentjedi, tapi bagaimana Anda memaksa pengalihan ke tampilan login untuk menggunakan POST? Ganti LoginManager.unauthorized_handler ? - person David White; 13.07.2016
comment
Cukup banyak ya, saya akan memperbarui jawaban saya - person valignatev; 13.07.2016