You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask Login异常:医师登录后短暂跳转回登录页问题

问题描述

系统包含医师(Physician)和患者(Patient)两类用户,患者登录功能正常,但医师登录成功跳转至医师仪表板后,页面仅短暂显示就自动重定向回登录页面。已参照患者登录逻辑修改医师登录的HTML及Python脚本,但问题仍未解决。

存在问题的医师登录相关代码

前端JS代码

document.getElementById('physicianLoginForm').addEventListener('submit', function(e) {
    e.preventDefault();

    // Get the email and password from the form
    var email = document.getElementById('physician_username').value;
    var password = document.getElementById('physician_password').value;

    // Send the login data to the Flask backend
    fetch('/handle_physician_login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            email: email,
            password: password
        })
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // Redirect to the physician dashboard if login is successful
            window.location.href = data.redirect;
        } else {
            // Display error message if login failed
            document.getElementById('errorMessage').textContent = data.message;
        }
    })
    .catch(error => console.error('Error:', error));
});

后端Python代码

class Physician(UserMixin):
    def __init__(self, id, email):
        self.id = id
        self.email = email

@login_manager.user_loader
def load_physician(user_email):
    conn = get_db_connection()
    if conn is None:
        return None
    try:
        cursor = conn.cursor()
        // Make sure to query the email column since user_email is an email
        cursor.execute("SELECT PhysicianId, WorkEmail FROM physicians WHERE WorkEmail=?", user_email)
        user_data = cursor.fetchone()
        if user_data:
        // Create the user object with the PhysicianId and Email
            return Physician(id=user_data.PhysicianId, email=user_data.WorkEmail)
        return None
    finally:
        conn.close()

@app.route('/handle_physician_login', methods=['POST'])
@limiter.limit("5 per minute")
def handle_physician_login():
    data = request.get_json()
    email = data['email']
    password = data['password']

    conn = get_db_connection()
    if conn is None:
        return jsonify({'success': False, 'message': 'Database connection failed'}), 500

    try:
        cursor = conn.cursor()
        cursor.execute("EXEC AuthenticatePhysician @Email=?", email)
        physician = cursor.fetchone()
        if physician and check_password_hash(physician.Password, password):
            user = Physician(physician.PhysicianId, email)
            login_user(user)
            return jsonify({'success': True, 'redirect': url_for('physician_dashboard')})

        else:
            return jsonify({'success': False, 'message': 'Invalid login credentials'}), 401
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 500
    finally:
        conn.close()
正常工作的患者登录相关代码

前端JS代码

<script>
    document.getElementById('patientLoginForm').addEventListener('submit', function(e) {
        e.preventDefault();

        // Get the email and password from the form
        var email = document.getElementById('Email').value;
        var password = document.getElementById('Password').value;

        // Send the login data to the Flask backend
        fetch('/handle_patient_login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                email: email,
                password: password
            })
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                // Redirect to the patient dashboard if login is successful
                window.location.href = data.redirect;
            } else {
                // Display error message if login failed
                document.getElementById('registrationMessage').textContent = data.message;
            }
        })
        .catch(error => console.error('Error:', error));
    });
</script>

后端Python代码

class Patient(UserMixin):
    def __init__(self, id, email):
        self.id = id
        self.email = email


@login_manager.user_loader
def load_user(user_email):
    conn = get_db_connection()
    if conn is None:
        return None
    try:
        cursor = conn.cursor()
        // Make sure to query the email column since user_email is an email
        cursor.execute("SELECT PatientID, Email FROM patients WHERE Email=?", user_email)
        user_data = cursor.fetchone()
        if user_data:
            // Create the user object with the PatientID and Email
            return Patient(id=user_data.PatientID, email=user_data.Email)
        return None
    finally:
        conn.close()


@app.route('/handle_patient_login', methods=['POST'])
@limiter.limit("5 per minute")
def handle_patient_login():
    data = request.get_json()
    email = data['email']
    password = data['password']

    conn = get_db_connection()
    if conn is None:
        return jsonify({'success': False, 'message': 'Database connection failed'}), 500

    try:
        cursor = conn.cursor()
        cursor.execute("EXEC AuthenticatePatient @Email=?", email)
        patient = cursor.fetchone()
        if patient and check_password_hash(patient.Password, password):
            user = Patient(patient.PatientID, email)
            login_user(user)
            return jsonify({'success': True, 'redirect': url_for('patient_dashboard')})
        else:
            return jsonify({'success': False, 'message': 'Invalid login credentials'}), 401
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 500
    finally:
        conn.close()
问题原因及解决方案

核心原因

Flask-Login 仅会使用一个被 @login_manager.user_loader 装饰的函数来加载登录用户。当前代码中,患者登录使用了 load_user 函数,而医师登录单独定义了 load_physician 函数,导致医师登录后,系统无法正确从 Session 中加载用户对象,仪表板路由检测到用户未登录,就会自动重定向回登录页。

解决步骤

  1. 合并用户加载逻辑
    将医师和患者的加载逻辑合并到同一个 load_user 函数中,先尝试加载患者,若不存在则加载医师:

    @login_manager.user_loader
    def load_user(user_email):
        conn = get_db_connection()
        if conn is None:
            return None
        try:
            cursor = conn.cursor()
            # 先查患者表
            cursor.execute("SELECT PatientID, Email FROM patients WHERE Email=?", user_email)
            user_data = cursor.fetchone()
            if user_data:
                return Patient(id=user_data.PatientID, email=user_data.Email)
            
            # 患者不存在则查医师表
            cursor.execute("SELECT PhysicianId, WorkEmail FROM physicians WHERE WorkEmail=?", user_email)
            user_data = cursor.fetchone()
            if user_data:
                return Physician(id=user_data.PhysicianId, email=user_data.WorkEmail)
            
            return None
        finally:
            conn.close()
    

    同时删除原来的 load_physician 函数。

  2. 确认医师仪表板路由权限
    确保医师仪表板的路由添加了 @login_required 装饰器,且没有额外的用户类型校验错误:

    @app.route('/physician_dashboard')
    @login_required
    def physician_dashboard():
        # 仪表板逻辑
        return render_template('physician_dashboard.html')
    
  3. 验证用户对象的唯一性
    确保 Physician 和 Patient 类的 id 属性不会出现重复(比如患者ID和医师ID使用不同的编号规则),避免加载用户时出现混淆。

内容的提问来源于stack exchange,提问作者37307554

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 13:06:19