pythonflaskflask-login

Flask: user can access other user session


I have built a small website with Flask, Flask-login and FLask-sqlalchemy with user login.

When in production:

To be noted that I have the same behavior with two different servers: pythonanywhere and O2switch. So, the problem should be on my side :/ (or the 2 servers have a wrong configurations ?)

In local, I have no issue (it is difficult to have the same conditions as in production with another device but let say that I have no issue when using Incognito mode of my browser as the second user).

The code I am using:

__init__.py

# library
from flask import Flask
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy

# modules
from mywebsite_flask.config import config_selection


# init extensions
db = SQLAlchemy()
login_manager = LoginManager()


# app set-up
def create_app(config_mode):
    app = Flask(__name__)
    app.config.from_object(config_selection[config_mode])

    # flask-login init
    login_manager.login_view = "auth_bp.login"
    login_manager.init_app(app)

    # database init
    db.init_app(app)
    from mywebsite_flask.auth.models import Customer
    with app.app_context():
        db.create_all()

    # add blueprints
    from mywebsite_flask.public.routes import public_bp
    app.register_blueprint(public_bp)
    from mywebsite_flask.auth.routes import auth_bp
    app.register_blueprint(auth_bp)

    app.app_context().push()

    return app

models.py

# library
from flask_login import UserMixin

# modules
from mywebsite_flask import db, login_manager


class Customer(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    email = db.Column(db.String, unique=True)
    password = db.Column(db.String)
    token_verification = db.Column(db.Boolean, default=False)

    def __repr__(self):
        return f"Customer #{self.id}:{self.email}>"


@login_manager.user_loader
def load_user(customer_id):  # customer found by unique id
    return Customer.query.get(int(customer_id))

auth.routes.py

# library
from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required, login_user, logout_user
from werkzeug.security import generate_password_hash

# modules
from mywebsite_flask import db
from mywebsite_flask.auth.models import Customer


# init
auth_bp = Blueprint("auth_bp", __name__)


@auth_bp.route("/login", methods=("GET", "POST"))
def login():
    if not current_user.is_authenticated:
        if request.method == "POST":
            email = request.form.get("email").lower()
            password = request.form.get("password")
            remember = True if request.form.get("remember") else False

            check_user = db.session.execute(
                db.select(Customer).filter_by(email=email)
            ).scalar_one_or_none()

            if not various_check(check_user):
                # check that none of them are None
                error_msg = "Un des champs requis est vide."
                flash(error_msg, category="error")
            else:
                login_user(check_user, remember=remember)
                return redirect(url_for("public_bp.home"))

        return render_template("auth/login.html")

    else:
        return redirect(url_for("core_bp.customer_home"))


@auth_bp.route("/logout", methods=("GET", "POST"))
@login_required
def logout():
    logout_user()
    return redirect(url_for("public_bp.home"))


# end

I have reviewed my code several times, looked at flask-login documentation and read some similar stackoverflow posts without being able to find a solution. Can someone already have the issue or see a problem with my code ?

Edit

As requested, a cookie: enter image description here

Please note that, when the problem is triggered: if user B connects after user A login, we see the session of user A but there is no cookie present on user B side (and still, we can see and use user A session).


Solution

  • OK, I have found the problem.

    In the app factory create_app() in init.py, I had app.app_context().push()

    I have added it as a shortcut at the beginning of the project. It was to easily access app.config parameters everywhere in the application.

    The problem was solved by:

    app.app_context().push() somehow interferes with the different sessions created on server (and more specifically on the current_user from flask login)

    (thanks @relent95 for your help)