Introduction

User authentication is a crucial aspect of web development, ensuring that only authorized users can access certain parts of your application. Flask-Login is a powerful extension for Flask, a popular Python web framework, that simplifies the implementation of user authentication. In this article, we’ll explore how to use Flask-Login to secure your Flask application with user authentication.

Getting Started with Flask-Login

Before diving into the implementation, make sure you have Flask installed. You can install it using:

bash
pip install Flask

Next, install Flask-Login:

bash
pip install Flask-Login

Now, let’s create a simple Flask application and set up Flask-Login.

python

# app.py

from flask import Flask, render_template
from flask_login import LoginManager

app = Flask(__name__)
app.config[‘SECRET_KEY’] = ‘your_secret_key’

login_manager = LoginManager(app)

Here, we’ve initialized a Flask application and set a secret key. The secret key is essential for security purposes, such as protecting against Cross-Site Request Forgery (CSRF) attacks. Additionally, we’ve created a LoginManager instance and associated it with our Flask app.

Creating a User Model

To use Flask-Login, you need to have a user model that represents the users of your application. Let’s create a simple user model using SQLAlchemy, a popular SQL toolkit for Python.

python

# models.py

from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin

db = SQLAlchemy()

class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
password = db.Column(db.String(100), nullable=False)

Make sure to install the required packages:

bash
pip install Flask-SQLAlchemy

Here, we’ve created a User class that inherits from db.Model and UserMixin. UserMixin provides default implementations for the methods required by Flask-Login. The User class has attributes for the user’s ID, username, and password.

Initializing the Database

Now, let’s initialize the database and create the necessary tables.

python

# app.py (continued)

app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘sqlite:///site.db’
db.init_app(app)

with app.app_context():
db.create_all()

This code configures the SQLite database and initializes it with our Flask app. The with app.app_context() block ensures that the database is created within the application context.

Implementing User Registration and Login Views

Now, let’s create views for user registration and login. We’ll use Flask-WTF for form handling.

bash
pip install Flask-WTF
python

# forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo

python

# app.py (continued)

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo

class RegistrationForm(FlaskForm):
username = StringField(‘Username’, validators=[DataRequired(), Length(min=2, max=20)])
password = PasswordField(‘Password’, validators=[DataRequired()])
confirm_password = PasswordField(‘Confirm Password’, validators=[DataRequired(), EqualTo(‘password’)])
submit = SubmitField(‘Sign Up’)

The RegistrationForm includes fields for username, password, and confirm password, along with validation rules.

Now, let’s create the registration and login routes in our app.py.

python

# app.py (continued)

from flask import redirect, url_for, flash
from flask_login import login_user, logout_user, login_required

@app.route(‘/register’, methods=[‘GET’, ‘POST’])
def register():
form = RegistrationForm()

if form.validate_on_submit():
new_user = User(username=form.username.data, password=form.password.data)
db.session.add(new_user)
db.session.commit()
flash(‘Your account has been created! You can now log in.’, ‘success’)
return redirect(url_for(‘login’))

return render_template(‘register.html’, form=form)

In the registration route, we create a new user if the form is valid and redirect the user to the login page.

python

# app.py (continued)

class LoginForm(FlaskForm):
username = StringField(‘Username’, validators=[DataRequired(), Length(min=2, max=20)])
password = PasswordField(‘Password’, validators=[DataRequired()])
submit = SubmitField(‘Login’)

python

# app.py (continued)

@app.route(‘/login’, methods=[‘GET’, ‘POST’])
def login():
form = LoginForm()

if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()

if user and user.password == form.password.data:
login_user(user)
flash(‘Login successful!’, ‘success’)
return redirect(url_for(‘home’))
else:
flash(‘Login unsuccessful. Please check your username and password.’, ‘danger’)

return render_template(‘login.html’, form=form)

In the login route, we validate the form, query the database for the user, and log in the user if the credentials are correct.

Creating the Home Page and Logout Functionality

Now, let’s create a simple home page that requires authentication to access.

python

# app.py (continued)

@app.route(‘/’)
@login_required
def home():
return render_template(‘home.html’)

The @login_required decorator from Flask-Login ensures that only authenticated users can access the home page.

Next, let’s implement the logout functionality.

python

# app.py (continued)

@app.route(‘/logout’)
@login_required
def logout():
logout_user()
flash(‘You have been logged out.’, ‘info’)
return redirect(url_for(‘login’))

The logout route logs out the user using logout_user() from Flask-Login and redirects them to the login page.

Creating HTML Templates

Now, let’s create HTML templates for the registration, login, and home pages.

html

<!-- templates/register.html -->

{% extends ‘base.html’ %}

{% block content %}
<h2>Register</h2>
<form method=“POST” action=“{{ url_for(‘register’) }}”>
{{ form.hidden_tag() }}
<div class=“form-group”>
{{ form.username.label(class=”form-control-label”) }}
{{ form.username(class=”form-control form-control-lg”) }}
</div>
<div class=“form-group”>
{{ form.password.label(class=”form-control-label”) }}
{{ form.password(class=”form-control form-control-lg”) }}
</div>
<div class=“form-group”>
{{ form.confirm_password.label(class=”form-control-label”) }}
{{ form.confirm_password(class=”form-control form-control-lg”) }}
</div>
<div class=“form-group”>
{{ form.submit(class=”btn btn-primary”) }}
</div>
</form>
{% endblock %}

html

<!-- templates/login.html -->

{% extends ‘base.html’ %}

{% block content %}
<h2>Login</h2>
<form method=“POST” action=“{{ url_for(‘login’) }}”>
{{ form.hidden_tag() }}
<div class=“form-group”>
{{ form.username.label(class=”form-control-label”) }}
{{ form.username(class=”form-control form-control-lg”) }}
</div>
<div class=“form-group”>
{{ form.password.label(class=”form-control-label”) }}
{{ form.password(class=”form-control form-control-lg”) }}
</div>
<div class=“form-group”>
{{ form.submit(class=”btn btn-primary”) }}
</div>
</form>
{% endblock %}

html

<!-- templates/home.html -->

{% extends ‘base.html’ %}

{% block content %}
<h2>Home</h2>
<p>Welcome, {{ current_user.username }}!</p>
<a href=“{{ url_for(‘logout’) }}” class=“btn btn-danger”>Logout</a>
{% endblock %}

In these templates, we’ve used Bootstrap for styling and included the necessary form fields.

Conclusion

Flask-Login provides a convenient way to implement user authentication in your Flask applications. In this article, we’ve covered the basic steps to set up Flask-Login, create a user model, handle user registration and login, and secure specific routes. By following these examples, you can enhance the security of your Flask applications and provide a better user experience.