คำขอ POST ของ Flask-Login กลายเป็นคำขอ GET หลังจากเข้าสู่ระบบ [ซ้ำกัน]

ฉันใช้ flask-login เพื่อจัดการการตรวจสอบสิทธิ์สำหรับแอปของฉัน ซึ่งเป็น API ที่คาดหวังส่วนหัว HTTP Basic Authorization เป็นส่วนหนึ่งของคำขอแต่ละรายการ (เพื่อให้ผู้ใช้สามารถเข้าสู่ระบบและสร้างคำขอได้โดยไม่ต้องกังวลกับเซสชัน คุกกี้ หรือต้องทำ เข้าสู่ระบบและขอแยกขั้นตอน)

คำขอของฉันได้ผลดังนี้:

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

นั่นคือคำขอ POST ไปยัง /api/group/48 กำลังถูกดักและเปลี่ยนเส้นทางไปยังตำแหน่งข้อมูล /login (ตามที่คาดไว้) สิ่งที่เกิดขึ้นใน /login ไม่มีการโต้ตอบ - ใช้ส่วนหัวการอนุญาตพื้นฐานและเข้าสู่ระบบผู้ใช้

หลังจากการเข้าสู่ระบบเสร็จสิ้น ลูกค้าจะถูกเปลี่ยนเส้นทางกลับไปที่ /api/group/48 - แต่คราวนี้เป็นคำขอ GET ไม่ใช่ POST และในแอปนี้ ตำแหน่งข้อมูล /api/group/48 คาดว่าจะมีเพียงข้อมูล POST เท่านั้น ดังนั้นจึงเกิดข้อผิดพลาด 405 (ไม่อนุญาตวิธีการ)

นี่เป็นพฤติกรรมที่คาดหวังของการเข้าสู่ระบบขวดหรือไม่ ฉันจะให้มันผ่านคำขอ POST ตามที่ส่งมาครั้งแรกได้อย่างไร (หรืออีกทางหนึ่ง ฉันควรใช้สถาปัตยกรรมที่แตกต่างกันเพื่อไม่ให้การเปลี่ยนเส้นทางไปที่ /login จากนั้นกลับไปที่ /api/group/48 และข้อมูล POST จะไม่สูญหาย)

ฉันไม่ได้รวมรหัสไว้ เนื่องจากฉันไม่คิดว่านี่เป็นปัญหาเฉพาะรหัส แต่ถ้าปรากฏว่าฉันทำอะไรผิด ฉันสามารถโพสต์โค้ดตัวอย่างได้

ขอบคุณทุกคนที่สามารถช่วยได้


person David White    schedule 13.07.2016    source แหล่งที่มา
comment
เป็นการยากที่จะพยายามตอบคำถามของคุณโดยไม่มีโค้ดตัวอย่าง คุณช่วยยกตัวอย่างเล็กๆ น้อยๆ ของปัญหา (เรียกใช้ได้ถ้าเป็นไปได้) ได้ไหม   -  person Quint    schedule 13.07.2016
comment
ฉันไม่เชื่อว่าโปรโตคอล HTTP อนุญาตให้มีการเปลี่ยนเส้นทางเช่นนั้น เมื่อการเข้าสู่ระบบการตรวจสอบสิทธิ์ขั้นพื้นฐานเสร็จสิ้น ฉันคิดว่าคำขอถัดไปในรอบนี้จะเป็นคำขอ GET   -  person Wayne Werner    schedule 13.07.2016


คำตอบ (2)


นี่เป็นมากกว่าการเปลี่ยนเส้นทาง (ซึ่งอาจยังอาจเป็นปัญหาสำหรับเบราว์เซอร์ / ไคลเอ็นต์บางตัว) ลูกค้าของคุณจะต้องจดจำเนื้อหาของคำขอเริ่มแรก และโพสต์ใหม่ในภายหลัง ไม่มีกลไกดังกล่าวอยู่ในข้อกำหนด HTTP

สิ่งที่คุณสามารถทำได้คือจดจำคำขอ (ในเซสชันเกี่ยวกับสิ่งที่คล้ายกัน) จากนั้นทำการเปลี่ยนเส้นทาง จากนั้นประมวลผลคำขอที่เก็บไว้ ฉันไม่คิดว่าจะมีทางลัดที่นี่

person frnhr    schedule 13.07.2016

หากคุณต้องการเปลี่ยนเส้นทางเป็น POST จริงๆ คุณสามารถทำได้ สมมติว่าคุณมีมุมมองที่มีการเปลี่ยนเส้นทางเช่นนี้ (นำมาจากเอกสารการเข้าสู่ระบบขวดอย่างไร้ยางอาย):

@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)

จากนั้น คำตอบนี้ เสนอราคา Wikipedia:

เว็บเบราว์เซอร์จำนวนมากใช้โค้ดนี้ในลักษณะที่ละเมิดมาตรฐานนี้ โดยเปลี่ยนประเภทคำขอของคำขอใหม่เป็น GET โดยไม่คำนึงถึงประเภทที่ใช้ในคำขอเดิม (เช่น POST) 1 ด้วยเหตุนี้ HTTP/1.1 (RFC 2616) จึงเพิ่มรหัสสถานะใหม่ 303 และ 307 เพื่อแยกความกำกวมระหว่างพฤติกรรมทั้งสอง โดยที่ 303 กำหนดให้เปลี่ยนประเภทคำขอเป็น GET และ 307 จะคงประเภทคำขอไว้ตามที่ส่งไปในตอนแรก

ดังนั้นคำตอบของคุณคือเปลี่ยนเส้นทางไปที่ flask.redirect(next or flask.url_for('index'), code=307)

โปรดทราบว่าคุณอาจต้องเปลี่ยนเส้นทางไปที่ login ดูเป็น POST เพื่อให้ใช้งานได้ คุณสามารถสร้างตัวจัดการที่ไม่ได้รับอนุญาตแบบกำหนดเองได้:

@login_manager.unauthorized_handler
def unauthorized():
    # do stuff
    return a_response
person valignatev    schedule 13.07.2016
comment
เป็นแนวคิดที่น่าสนใจ valentjedi แต่คุณจะบังคับให้เปลี่ยนเส้นทางไปยังมุมมอง login เพื่อใช้ POST ได้อย่างไร แทนที่ LoginManager.unauthorized_handler ? - person David White; 13.07.2016
comment
ใช่แล้ว ฉันจะอัปเดตคำตอบของฉัน - person valignatev; 13.07.2016