How to add authentication with Flask Login

- Andrés Cruz

En español
How to add authentication with Flask Login

You can use the Flask-Login module to control access. admin provide user sessions for Flask: login, logoff, and remember sessions.

  Flask-Login allows:

  • Store the id of the active user in the Flask session and it will allow you to easily log in and out.
  • Allows you to switch views to online (or offline) users. (Login required)
  • Handling the "remember me" functionality, usually complicated.
  • Help protect your users' sessions from being stolen by cookie stealers.

However, it will not allow:

  • Imposing a particular database or other storage method on it. You are totally in charge of how the user loads.
  • Restrict you from using usernames and passwords, OpenID or any other authentication method.
  • Handle permissions beyond "login or not".
  • Manage user registration or account recovery.

The Flask ecosystem

Flask makes it easy to compose orthogonal applications into a larger, more complex one in the same way that functions are composed in functional languages. Take, for example, an application to store messages like a forum, although in frameworks like Django, there are all kinds of complex applications that you could adapt with a lot of effort, in Flask, using extensions like:

Flask-Admin for database management
Flask-Assets for asset management
Flask-DebugToolbar for debugging and profiling.
Flask-Markdown for forum posts
Flask-Script for basic commands
Flask-Security for authentication
Flask-SQLAlchemy for database queries
Flask-WTF for forms
With such a long list, it's almost surprising that all applications can work together without creating dependencies on each other (or rather, amazing if you're coming from Django), but Flask extensions often follow the Unix philosophy of "make a good thing”. This is excellent since, since there are no relationships between these dependencies, you can customize your development quite a bit.

 

We will see how to use Flask Login to have a complete and basic Login system in a few moments in our application.

To follow the tutorial you have to be clear about the following aspects:

  • Manage virtual spaces, to create our application
  • Know the first steps with Flask

About Flask Login

Flask-Login is an extension to the Flask web framework that provides user session management, such as login, logout, and session persistence. To use Flask-Login, we create a model for the user that defines the methods and parameters required by this extension, such as is_authenticated, is_active, and is_anonymous, and then initializes the extension in their Flask application.

Flask-Login is provided by an excellent package that allows us to handle the common tasks of logging in and out, as well as remembering credentials for a long time.

It works in a simple way in which we need a user model and as a result of this we can compare credentials and log in:

With our authenticated user we can perform operations such as:

  • Log out easily.
  • Restrict view to online (or offline) users.

Install Flask Login

With our application created, we are going to install the package with:

pip install flask-login

The first thing we need is to install the package, since as you should know at this point, Flask is a micro framework and it brings the minimum necessary to work; essentially basic core functions, routing, security, and a template engine for HTML; for everything else, there is Mastercard or install third-party packages either from Python or from the framework.

Configure it in your app

Let's go to our __init__ in proyect/app/:

from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)

And with this we are ready to use it.

We are going to have a module or application called app:

project/app/user in which we will create the typical MVC in Flask applications:

Controllers, views.py:

from flask import Blueprint,session, render_template, request, redirect, url_for, flash, get_flashed_messages
from app.user.models import User
from app.user.forms import LoginForm, RegisterForm
from app import db, login_manager
from flask_login import current_user,login_user, login_required, logout_user
from werkzeug.security import generate_password_hash
userBp = Blueprint('user',__name__)
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(user_id)
@userBp.route('/login', methods=('GET', 'POST'))
def login():
   #print(current_user.name)
   form = LoginForm(meta={'csrf':False})
   if form.validate_on_submit():
      user = User.query.filter_by(username=form.username.data).first()
      if user and user.check_password(form.password.data):
         # registrar sesion
         login_user(user, remember=True)
         flash("Bienvenido de nuevo "+user.username)
         print("Vien")
         return redirect(url_for('chat.hello_world'))
      else:
         print("Malo")
         flash("Usuario o contraseña incorrectos",'danger')
   if form.errors:
      print(form.errors)
      flash(form.errors,'danger')
   return render_template('user/login.html',form=form)
@userBp.route('/logout')
@login_required
def logout():
   logout_user()
   return redirect(url_for('user.login'))
@userBp.route('/register', methods=('GET', 'POST'))
def register():
   print(session)
   print(current_user)
   form = RegisterForm(meta={'csrf':False})
   if form.validate_on_submit():
      if User.query.filter_by(username=form.username.data).first():
         flash("El usuario ya existe en el sistema",'danger')
      else:
         #crear usuario
         u = User()
         u.name = form.username.data
         u.username = form.username.data
         u.password = generate_password_hash(form.password.data)
         u.email = form.email.data
         login_user(u, remember=True)
         flash("Usuario creado con éxito")
         return redirect(url_for('user.register'))
   if form.errors:
      flash(form.errors,'danger')
   return render_template('user/register.html',form=form)
@login_required
def logout():
    logout_user()
    return redirect(url_for('user.login'))

Models models.py

from flask_login import UserMixin
from app import db
from werkzeug.security import check_password_hash,generate_password_hash
class User(db.Model,UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    email= db.Column(db.String(100), unique=True)
    username= db.Column(db.String(100), unique=True)
    password= db.Column(db.String(400))
    name= db.Column(db.String(100))
    #__tablename__ = 'users'
    def check_password(self, password):
        return check_password_hash(self.password,password)

Forms forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, HiddenField
from wtforms.validators import InputRequired, EqualTo
class LoginForm(FlaskForm):
    username = StringField('Usuario', validators=[InputRequired()])
    password = PasswordField('Contraseña', validators=[InputRequired()])
class RegisterForm(FlaskForm):
    username = StringField('Usuario', validators=[InputRequired()])
    email = StringField('Email', validators=[InputRequired()])
    password = PasswordField('Contraseña', validators=[InputRequired(),EqualTo('confirm')])
    confirm  = PasswordField('Repetir Contraseña')

Templates

Templates login, /app/templates/user/login

<form action="{{ url_for('user.login') }}" method="POST">
    <div class="form-group">
        {{ form.username.label }} 
        {{ form.username(class="form-control") }}
    </div>
    <div class="form-group">
        {{ form.password.label }} 
        {{ form.password(class="form-control") }}
    </div>
    <input class="btn btn-success" type="submit" value="Enviar">
</form>

Templates register, /app/templates/user/register

<form action="{{ url_for('user.register') }}" method="POST">
    <div class="form-group">
        {{ form.username.label }} 
        {{ form.username(class="form-control") }}
    </div>
    
    <div class="form-group">
        {{ form.email.label }} 
        {{ form.email(class="form-control") }}
    </div>
    <div class="form-group">
        {{ form.password.label }} 
        {{ form.password(class="form-control") }}
    </div>
    <div class="form-group">
        {{ form.confirm.label }} 
        {{ form.confirm(class="form-control") }}
    </div>
    <input class="btn btn-success" type="submit" value="Enviar">
</form>

This example defines a user model that has an ID attribute, it also defines its view and route for login, login, register among others; protected routes are defined using the @login_required decorator, which ensures that only authenticated users can access the function. The logout route logs the user out and redirects the user to the login page.

You can also customize the behavior of Flask-Login using various configuration options, as you can see in the official documentation.

Remember that the source code of the project can be seen here:

https://github.com/libredesarrollo/curso-flask-socketio

Or here:

https://github.com/libredesarrollo/curso-flask-base

 

And remember that we are not using styles:

Form Login
Form Login

Remember that this material is part of my course and complete book on flask.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.