Authentication with sub routes in SQLAlchemy in flask

131 Views Asked by At

Hi I was implementing a login verification to restrict certain routes on a website. Users are created successfully and if a user does not exist, they cannot log in. However, when attempting to access a route that requires a login, changing the username still allows access to the route. Do you know why this might be happening?

This is the code:

from flask import Flask, redirect, flash, request, render_template, url_for, make_response
import secrets
from flask_login import login_required, LoginManager, login_user, UserMixin
from flask_sqlalchemy import SQLAlchemy


app = Flask("test")
secret_key = secrets.token_hex(16)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SECRET_KEY'] = secret_key
db = SQLAlchemy(app)


login_manager = LoginManager(app)
login_manager.init_app(app)

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    games = db.relationship('Game', backref='user', lazy=True)

class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    moves= db.Column(db.String(500), nullable=False)
    status = db.Column(db.String(5), nullable=False)#Si o no
    color = db.Column(db.String(20), nullable=False)


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
    
@login_manager.unauthorized_handler
def unauthorized():
    return redirect(url_for("login"))


@app.route('/')
def home():
    return render_template('begin.html')

@app.route('/login',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        name= request.form['user']
        psw = request.form['psw']
        user = User.query.filter_by(name=name).first()

        if user and user.password==psw:
            login_user(user)
            route = '/'+str(user.name)+'/home'
            return redirect(route)
        else:
            return render_template('login.html',resultado='user not found')
    else:
        return render_template('login.html')
    

       
@app.route('/registrar',methods=['GET','POST'])
def registrar():
    if request.method == 'POST':
        user = request.form['user']
        email = request.form['email']
        psw = request.form['psw']
        confirm_psw = request.form['confirm_psw']

        if psw != confirm_psw:
            return render_template('registrar.html',validacion="Passwords do not match")
        
        
        new_user = User(name=name, email=email, password=psw)
        db.session.add(new_user)
        db.session.commit()
        
        return redirect('/login')
    else:
        return render_template('registrar.html')

@app.route('/<user>/home',methods=['GET','POST'])
@login_required
def main_page(user):
        return render_template('home.html',user=user)

UPDATE

After some research I know the problem is with the url in the main_page. When I change the user in the url the current_user doesn't change so the current_user is the user that make login and the login_required doesn't look for the new user. I don't know if I am correct because I tried to fixed it but it doesn't work

1

There are 1 best solutions below

2
Christopher Poulsen On

The first thing to underestand is that your logged in user is being loaded every time they go to a route, and we define this behaviour in this seccion of code:

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

Whats happening here is that we are loading the user using it's user_id which is stored in flask's session object, as you can see in this line of code User.query.get(int(user_id))

So the reazon it doesn't prompt the user to login again is because the user_id hasn't changed even when the username was changed.

What you could do if you want that to happen is to clear the session when you change the username, like this:

from flask import session

# Your code where you change the username
session.clear()