In this chapter, we focus on the user login and authentication. We study the Flask-login package, and how we can use its functionalities to allow the user to log in, log out and to restrict access to some routes if the user is not authenticated. We also change the layout of our app if the user is logged in or logged out.
This section allows us to customize forms validators to help the user to understand the right information to introduce in our app.
This section studies the Flask-login package and its functionalities that allow us to improve the log in, log out and other aspects of our app related to user authentication.
This chapter is very specific to user authentication, and there is not much that can be done within our app. Therefore, the weekly challenge consists in go through the material of the chapter and understand how the Flask-login package can be useful in our app.
The links to the YouTube videos, and the GitHub account for this section are below:
All the information in this section has been taken from the next links:
We customize the messages disclosed to the user. If for example, we try to register by using the same username or email, we get an ugly message. To avoid those messages that could not be very useful for the users of our app, we can customize our WTF Forms Validators.
In the package users, in the forms.py file.
class MyForm(Form):
name = StringField('Name', [InputRequired()])
def validate_name(form, field):
if len(field.data) > 50:
raise ValidationError('Name must be less than 50 characters')
from capp.models import User
from wtforms.validators import ValidationError
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('That username is taken.//
Please choose a different one.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('That email is taken. //
Please choose a different one.')
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField,
BooleanField
from wtforms.validators import DataRequired, Length, Email,
EqualTo, ValidationError
from capp.models import User
class RegistrationForm(FlaskForm):
username = StringField('Username',
validators=[DataRequired(), Length(min=2, max=30)])
email = StringField('Email',
validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password',
validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Sign Up')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('That username is taken. //
Please choose a different one.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('That email is taken. //
Please choose a different one.')
The links to the YouTube video, and the GitHub account for this section are below:
All the information in this section has been taken from the next links:
Flask-Login provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time.
It will
from flask_login import LoginManager
login_manager = LoginManager()
The login manager contains the code that lets your application and Flask-Login work together, such as how to load a user from an ID, where to send users when they need to log in, and the like.
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
It should return None (not raise an exception) if the ID is not valid. (In that case, the ID will manually be removed from the session and processing will continue.)
In this section, we use Flask-login in our application. We introduce four changes that allow us to use different Flask-login functionalities.
pip install flask-login
from flask_login import LoginManager
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
login_manager= LoginManager(application)
from capp import login_manager
from flask_login import UserMixin
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin)
from flask_login import LoginManager
login_manager= LoginManager(application)
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
from capp import login_manager
from flask_login import UserMixin
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
from capp.users.forms import RegistrationForm
from capp.models import User
from capp import db, bcrypt
from flask_login import login_user
users=Blueprint('users',__name__)
@users.route('/register', methods=['GET','POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user_hashed_password = //
bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username=form.username.data, email=form.email.data, //
password=user_hashed_password)
db.session.add(user)
db.session.commit()
flash('Your account has been created! Now, you are able to //
login!', 'success')
return redirect(url_for('users.login'))
return render_template('users/register.html', //
title='register', form=form)
from flask_login import login_user
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
flash('You have logged in! Now, you can start to use our App!', 'success')
else:
flash('Login Unsuccessful. Please check email and password!', 'danger')
login_user(user, remember=form.remember.data)
In this section, we focus on three different uses of Flask-login that are useful for our app.
from flask_login import current_user
if current_user.is_authenticated:
return redirect(url_for('home.home_home'))
from flask_login import logout_user
@users.route('/logout')
def logout():
logout_user()
return redirect(url_for('home.home_home'))
from flask_login import login_required
@carbon_app.route('/carbon_app')
@login_required
from flask import render_template, Blueprint, redirect, flash,
url_for, request
from capp.users.forms import RegistrationForm, LoginForm
from capp.models import User
from capp import db, bcrypt
from flask_login import login_user, current_user, logout_user
users=Blueprint('users',__name__)
@users.route('/register', methods=['GET','POST'])
def register():
...
@users.route('/login', methods=['GET','POST'])
def login():
form = LoginForm()
if current_user.is_authenticated:
return redirect(url_for('home.home_home'))
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password,
form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
flash('You have logged in! Now, you can start to
use our Carbon App!', 'success')
return redirect(next_page) if next_page else
redirect(url_for('home.home_home'))
else:
flash('Login Unsuccessful. Please check email and password!',
'danger')
return render_template('users/login.html', title='login', form=form)
@users.route('/logout')
def logout():
logout_user()
return redirect(url_for('home.home_home'))
@carbon_app.route('/carbon_app')
@login_required
@carbon_app.route('/carbon_app/new_entry')
@login_required
@carbon_app.route('/carbon_app/your_data')
@login_required
from flask import request
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
flash('You have logged in! Now, you can start to use our Carbon App!', 'success')
return redirect(next_page) if next_page else redirect(url_for('home.home_home'))
else:
In this section, we introduce some changes that allows us to accommodate the changes introduced in the routes.py files. When the user has logged in, we do not want that the register and the log in links appear in our app, since that could confound the user. Therefore, as soon as the user has logged in, we change the navigation bar, and the home page.
The links to the YouTube video, and the GitHub account for this section are below:
{% if current_user.is_authenticated %}
<nav>
<ul>
<li>
<a href="{{url_for('users.logout')}}">Logout</a>
</li>
<li>
<a href="{{url_for('home.home_home')}}">Home</a>
</li>
<li>
<a href="{{url_for('methodology.methodology_home')}}">Methology</a>
</li>
<li>
<a href="{{url_for('carbon_app.carbon_app_home')}}">Carbon App</a>
</li>
</ul>
</nav>
{% else %}
<nav>
<ul>
<li>
<a href="{{url_for('users.register')}}">Register</a>
</li>
<li>
<a href="{{url_for('users.login')}}">Login</a>
</li>
<li>
<a href="{{url_for('home.home_home')}}">Home</a>
</li>
<li>
<a href="{{url_for('methodology.methodology_home')}}">Methology</a>
</li>
<li>
<a href="{{url_for('carbon_app.carbon_app_home')}}">Carbon App</a>
</li>
</ul>
</nav>
{% endif %}
{% if current_user.is_authenticated %}
{% else %}
<div class="container_buttons_links_header_home">{
<div class="btn">
<a href="{{url_for('users.register')}}"
class="btn btn-primary btn-lg mr-2",
style="background-color:#007bff;">Register</a>
</div>
<div class="btn">
<a href="{{url_for('users.login')}}"
class="btn btn-primary btn-lg mr-2",
style="background-color:#007bff;">Login</a>
</div>
</div>
{% endif %}
This chapter is very specific to user authentication, and there is not much that can be done within our app. Therefore, the weekly challenge consists in go through the material of the chapter and understand how the Flask-login package can be useful in our app.