In this section, we will cover how to implement user login and logout functionality in a Flask application. This is a crucial part of any web application that requires user authentication. We will use Flask-Login, a popular extension that provides user session management for Flask.

Key Concepts

  1. Flask-Login: An extension that manages user sessions in Flask applications.
  2. User Model: A model that represents the user in the database.
  3. Login Manager: A Flask-Login component that handles user session management.
  4. User Authentication: The process of verifying the identity of a user.
  5. User Session: A session that keeps track of the logged-in user.

Setting Up Flask-Login

First, you need to install Flask-Login:

pip install flask-login

Next, let's set up Flask-Login in our Flask application.

Step 1: Initialize Flask-Login

In your app.py or main application file, initialize Flask-Login:

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

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'  # Redirect to login page if not authenticated
login_manager.login_message_category = 'info'  # Flash message category

Step 2: Create User Model

Create a User model that includes the necessary fields and methods required by Flask-Login:

from flask_login import UserMixin

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)
    password = db.Column(db.String(60), nullable=False)

    def __repr__(self):
        return f"User('{self.username}', '{self.email}')"

Step 3: User Loader Function

Define a user loader function that Flask-Login will use to load a user from the database:

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

Implementing User Login

Step 1: Create Login Form

Create a login form using Flask-WTF:

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

class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    remember = BooleanField('Remember Me')
    submit = SubmitField('Login')

Step 2: Create Login Route

Create a route to handle the login form submission:

from flask import render_template, url_for, flash, redirect, request
from flask_login import login_user, current_user, logout_user
from werkzeug.security import check_password_hash

@app.route("/login", methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and check_password_hash(user.password, form.password.data):
            login_user(user, remember=form.remember.data)
            next_page = request.args.get('next')
            return redirect(next_page) if next_page else redirect(url_for('home'))
        else:
            flash('Login Unsuccessful. Please check email and password', 'danger')
    return render_template('login.html', title='Login', form=form)

Step 3: Create Login Template

Create a login.html template to render the login form:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <form method="POST" action="{{ url_for('login') }}">
        {{ form.hidden_tag() }}
        <div>
            {{ form.email.label }}<br>
            {{ form.email(size=32) }}<br>
        </div>
        <div>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}<br>
        </div>
        <div>
            {{ form.remember() }} {{ form.remember.label }}<br>
        </div>
        <div>
            {{ form.submit() }}
        </div>
    </form>
</body>
</html>

Implementing User Logout

Step 1: Create Logout Route

Create a route to handle user logout:

@app.route("/logout")
def logout():
    logout_user()
    return redirect(url_for('home'))

Step 2: Add Logout Link

Add a logout link to your navigation bar or wherever appropriate:

<a href="{{ url_for('logout') }}">Logout</a>

Practical Exercise

Exercise: Implement User Login and Logout

  1. Objective: Implement user login and logout functionality in your Flask application.
  2. Steps:
    • Install Flask-Login.
    • Initialize Flask-Login in your application.
    • Create a User model.
    • Define a user loader function.
    • Create a login form using Flask-WTF.
    • Create a login route and template.
    • Create a logout route and add a logout link.

Solution

Follow the steps outlined in this section to implement the user login and logout functionality.

Common Mistakes and Tips

  • Common Mistake: Not setting the SECRET_KEY in your Flask application. This is required for session management.
  • Tip: Always hash passwords before storing them in the database. Use werkzeug.security.generate_password_hash and check_password_hash for this purpose.
  • Common Mistake: Forgetting to check if the user is already authenticated in the login route. This can lead to unnecessary login attempts.
  • Tip: Use current_user.is_authenticated to check if the user is already logged in.

Conclusion

In this section, we covered how to implement user login and logout functionality using Flask-Login. We learned how to set up Flask-Login, create a user model, handle user authentication, and manage user sessions. This is a fundamental part of building secure web applications with Flask. In the next section, we will explore password hashing to enhance the security of user credentials.

© Copyright 2024. All rights reserved