Flask login - csemanish12/flask_blog GitHub Wiki

Flask-login provides better implementation of user session . so we will be using flask-login package instead of session.

lets install the flask login

pip install flask-login

Lets add this to initialization of our application. we will import LoginManager and create an instance of it.

blog/_init_.py

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

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SECRET_KEY'] = 'mysecretkey'
db = SQLAlchemy(app)
login_manager = LoginManager(app)

from blog import routes

The way that this works is, we add some functionality to our model(User) and it will handle all the user sessions for us in the background.

lets open our models.py and add a method named user_loader that will load the user based on user_id stored in session. We will use the decorator login_manager.user_loader to indicate flask that user_loader method should be used for loading the user.

The extension(flask-login) expects our User model to have certain methods and properties. These properties/methods are is_active, is_authenticated, is_anonymous and get_id. We can create these properties/methods by ourselves. But, these properties are already implemented by UserMixin class of flask-login. so we can simply inherit UserMixin class in our User model to have these properties in our user model.

Our models.py will look like this now.

from blog import db, login_manager
from flask_login import UserMixin


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


class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
    password = db.Column(db.String(60), nullable=False)

lets modify our login route to see how this works. we will import login_user from flask-login and update our login route as follows

.
from flask_login import login_user
.
.
@app.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.password == form.password.data:
            login_user(user)
            flash(f'Login Successful', 'success')
            return redirect("/")
        else:
            flash(f'Incorrect email/password', 'danger')
    return render_template('login.html', form=form)

we have successfully logged in user. But if the user tries to navigate to login or registration page, we are not restricting them even though they are already logged in. lets redirect the user to home page if they try to navigate to login or registration route while being logged in.

We can get the current user by importing current_user from flask-login. The current_user has property called is_authenticated which returns true if the user has provided valid login credentials while logging in.

lets update our login route as follows:

.
from flask_login import current_user
.
@app.route("/login", methods=["GET", "POST"])
def login():
    if current_user.is_authenticated:
        return redirect("/")
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.password == form.password.data:
            login_user(user)
            flash(f'Login Successful', 'success')
            return redirect("/")
        else:
            flash(f'Incorrect email/password', 'danger')
    return render_template('login.html', form=form)

similarly, we will update our registration route as follows:

@app.route("/registration", methods=["GET", "POST"])
def register():
    if current_user.is_authenticated:
        return redirect("/")
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data, password=form.password.data)
        db.session.add(user)
        db.session.commit()
        flash(f'your account has been created! you can now log in', 'success')
        return redirect("/")
    return render_template('register.html', form=form)

Implementation can be found over this commit