[Python] How to handle user logging in with flask in python?

Discussão em 'Python' iniciado por Stack, Fevereiro 11, 2025.

  1. Stack

    Stack Membro Participativo

    I'm developing a basic web app with python flask, and I'm trying to modify some of the templates I use based on whether or not there is a user logged in. I'm using mongoDB to store user data. Below is the content of my authorisation script, containing the definition of the User model, registration and login methods as well as a helper check_login method:

    auth_blueprint = Blueprint('auth', __name__, template_folder='templates')

    # Setup Flask-Login and Bcrypt
    bcrypt = Bcrypt()
    login_manager = LoginManager()
    login_manager.login_view = "auth.login"


    # MongoDB configuration
    mongo_uri = config.mongo_uri
    client = MongoClient(mongo_uri)
    db = client[config.DB_NAME]
    users_collection = db["users"]

    # User class for Flask-Login
    class User(UserMixin):
    def __init__(self, id, username, password):
    self.id = id
    self.username = username
    self.password = password

    @staticmethod
    def get(user_id):
    user_data = users_collection.find_one({"_id": user_id})

    if user_data:
    return User(str(user_data["_id"]), user_data["username"], user_data["password"])
    return None

    def get_id(self):
    return self.id


    @login_manager.user_loader
    def load_user(user_id):
    print(f'load_user method is called and the user_id is {user_id}')

    try:
    return User.get(user_id)
    except:
    return None

    @auth_blueprint.route("/register", methods=["GET", "POST"])
    def register():
    if request.method == "POST":
    username = request.form["username"]
    password = request.form["password"]
    confirmed_password = request.form["repeat-password"]

    if not username:
    flash("Please enter a username.", "danger")
    return redirect(url_for("auth.register"))

    if users_collection.find_one({"username": username}):
    flash("Username already exists!", "danger")
    return redirect(url_for("auth.register"))

    if not password:
    flash("Please enter a password.", "danger")
    return redirect(url_for("auth.register"))

    if not confirmed_password:
    flash("Please confirm the password.", "danger")
    return redirect(url_for("auth.register"))

    if password != confirmed_password:
    flash("Passwords must match!", "danger")
    return redirect(url_for("auth.register"))

    hashed_password = bcrypt.generate_password_hash(password).decode("utf-8")
    users_collection.insert_one({"username": username, "password": hashed_password})
    flash("Registration successful!", "success")
    return redirect(url_for("auth.login"))

    return render_template("register.html")

    @auth_blueprint.route("/login", methods=["GET", "POST"])
    def login():
    if request.method == "POST":
    username = request.form["username"]
    password = request.form["password"]

    # Check if the user exists and credentials are valid
    user_data = users_collection.find_one({"username": username})
    print(user_data)
    if user_data and bcrypt.check_password_hash(user_data["password"], password):
    session.clear()
    user = User(str(user_data['_id']), user_data['username'], user_data['password'])
    print(f'User id is {user.id}')
    result = login_user(user, remember=True, duration=timedelta(days=7), force=True)
    session.modified = True
    print(f'Is user authenticated in login function: {current_user._get_current_object().is_authenticated}')
    # print(f'Current user type is {type(current_user.is_authenticated)}')
    if result:
    print("Loggin successful!")
    #print(f"Session after login: {session}") # Inspect session object
    flash("Login successful!", "success")
    return redirect(url_for("index"))
    else:
    print("Something went wrong :(")

    return redirect(url_for("auth.login"))
    # session['username'] = user.username



    # if not helpers.url_has_allowed_host_and_scheme(next, request.host):
    # return abort(400)


    else:
    flash("Invalid credentials!", "danger")

    return render_template("login.html")



    @auth_blueprint.route("/check_login")
    def check_login():
    print(f'Is user authenticated in check_login function: {current_user._get_current_object().is_authenticated}')
    print(type(current_user._get_current_object()))
    if current_user._get_current_object().is_authenticated:
    return f"User {current_user.name} is logged in."
    else:
    return "No user is logged in."



    P.S. The html part that is supposed to change based on user logging in is also dependent on the current_user._get_current_object().is_authenticated attribute, so I've omitted it as it seemded redundant. I'd also like to note that the _get_current_object() method of the current_user proxy doesn't change anything and I'm using it interchangeably for testing purposes.

    I've looked through other similiar questions and official documentation, but no luck. It seems to me that the problem boils down to the fact the current_user proxy is not remembered correctly once i redirect it from the login function; debugging during the login function shows that the current_user is set to an instance of my User class and the attribute is_authenticated value is set to True, but once I redirect to the check_login() function the current_user proxy defaults to an object of type AnonymousUserMixin. I suspect something is not right with my handling of session properties, but I can't figure it out.

    EDIT:

    The problem was in the load_user function, I tried to get the Id of the object without converting to BSON format that MongoDB uses. The corrected method is displayed below. Leaving the question up might help someone with a similiar trivial issue.

    @login_manager.user_loader
    def load_user(user_id):
    user_data = users_collection.find_one({"_id": ObjectId(user_id)})
    if user_data:
    return User(str(user_data['_id']), user_data['username'], user_data['password'])
    return None

    Continue reading...

Compartilhe esta Página