Lesson 1
Protecting Routes with Authentication Middleware
Protecting Routes with Authentication Middleware

Welcome to the first lesson of our course on securing a Flask MVC application. In this lesson, we'll explore how to implement an authentication middleware to protect the routes in our app. This middleware is vital because it ensures that only authorized users have access to specific features. For our ToDo app, it will serve as a gatekeeper, safeguarding user routes and enhancing security.

Think of an authentication middleware as a checkpoint that verifies a user's credentials before permitting access to designated areas of the application. By the end of this lesson, your app will be fortified with this indispensable security feature, ready to prevent unauthorized access.

Lesson Overview

In this lesson, we will cover the following key topics to secure our Flask ToDo app:

  1. Creating the Authentication Page: Design a user interface for login and registration to facilitate user authentication.
  2. Implementing the User Controller: Establish a controller to handle the connection between the authentication page and the backend.
  3. Developing the Authentication Middleware: Develop middleware to intercept requests and verify user authentication status.
  4. Integrating Middleware into the Flask App: Seamlessly incorporate the authentication middleware into the app to protect routes.

By the end of this lesson, you will be equipped with the skills to implement robust authentication middleware in your Flask application, enhancing its security and accessibility management.

Creating the Authentication Page

The first step in building an authentication system is to provide a user interface for login and registration. Let's create a new auth.html template for our authentication page inside our /templates directory:

HTML, XML
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Login / Register</title> 7 <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> 8</head> 9<body> 10 <h1>Login or Register</h1> 11 12 <!-- Form for registration and login --> 13 <form method="POST"> 14 <label for="username">Username:</label> 15 <input type="text" id="username" name="username" required><br><br> 16 17 <label for="password">Password:</label> 18 <input type="password" id="password" name="password" required><br><br> 19 20 <!-- Buttons to either register or login --> 21 <button type="submit">Login</button> 22 <button type="submit">Register</button> 23 </form> 24</body> 25</html>

This HTML code provides a simple form for user login and registration. It includes fields for a username and password, as well as buttons to submit the form. For now, we will not add any actions to these buttons, since we just need a page to redirect unauthenticated users.

Implementing the User Controller

Next, we'll create a controller to handle routes related to users, such as rendering the authentication page, and later handling registration and login.

Here's how you set up the controllers/user_controller.py:

Python
1from flask import Blueprint, render_template 2 3user_controller = Blueprint('user', __name__) 4 5# Route to render the authentication page 6@user_controller.route('/auth', methods=['GET']) 7def auth_page(): 8 return render_template('auth.html')

In this code, we use Flask's Blueprint to modularize our application. Inside this blueprint we define the /auth route for rendering the authentication page. This controller lays the groundwork for managing user authentication.

Developing the Authentication Middleware

Now, let's create an authentication_middleware.py file in the middlewares directory. This file ensures users can only access protected parts of the app if they are logged in.

Here's the middleware code with comments:

Python
1from flask import session, redirect, url_for, request 2 3def require_login_middleware(app): 4 # Set up the middleware to run before each request 5 @app.before_request 6 def require_login(): 7 # Check if the current endpoint is not in the allowed list 8 if request.endpoint not in ['user.auth_page', 'static']: 9 # Verify if 'user_id' is in the session; if not, the user is not logged in 10 if 'user_id' not in session: 11 # Redirect unauthenticated users to the authentication page 12 return redirect(url_for('user.auth_page'))

How It Works:

  1. Function Setup: The require_login_middleware function is defined to check authentication. It runs require_login before every request.
  2. URL Check: require_login checks if the current endpoint is an authentication page or a static file (like images or stylesheets). These should be accessible without login, so they are excluded from the check.
  3. Session Check: It looks for user_id in the session. Without it, the user isn't logged in. For now, no users will have user_id in the session since we haven't implemented the login route yet.
  4. Redirect: If user_id is absent, the user is redirected to /auth to log in, protecting other routes.
Integrating Middleware into the Flask App

Finally, let's bring everything together by integrating this middleware into our Flask app. We will update the app.py file:

Python
1from flask import Flask 2from controllers.todo_controller import todo_controller 3from controllers.theme_controller import theme_controller 4from controllers.user_controller import user_controller 5from middlewares.error_handler import setup_error_handler 6from middlewares.authentication_middleware import require_login_middleware 7from models import db 8from config import Config 9 10app = Flask(__name__) 11 12app.config.from_object(Config) 13 14app.secret_key = 'your_unique_secret_key' 15 16db.init_app(app) 17 18with app.app_context(): 19 db.create_all() 20 21setup_error_handler(app) 22 23# Setup authentication middleware 24require_login_middleware(app) 25 26# Register user controller blueprint 27app.register_blueprint(user_controller) 28 29app.register_blueprint(todo_controller) 30app.register_blueprint(theme_controller) 31 32if __name__ == '__main__': 33 app.run(host='0.0.0.0', port=3000, debug=True)

In this file, we initialize the Flask app, set up session management with a secret key, integrate our authentication middleware using the require_login_middleware(app) function and register the user_controller next to our already implemented controllers.

Accessing Protected Routes

When a user tries to access the / route or any other route within the application, the authentication middleware takes action. The middleware checks if the user is authenticated by verifying the presence of a user_id in the session. If the user_id is not found in the session, this indicates that the user is not logged in. Consequently, the middleware intercepts the request and redirects the user to the authentication page /auth.

As depicted in the diagram, when a route is accessed, the middleware evaluates whether the user is authenticated. If not (i.e., "No" path), the user is redirected to the /auth page. If the user is authenticated (i.e., "Yes" path), access to the requested route is granted. This mechanism ensures that all protected routes are only accessible to authenticated users, effectively acting as a security layer to safeguard the application's restricted areas.

Summary and Preparation for Practice

You have built a foundational understanding of adding authentication middleware to your Flask ToDo app and learned how to create a user authentication page, set up a user controller, and integrate a middleware to secure routes.

Now, you're ready to apply this knowledge in hands-on practice exercises. These exercises will reinforce what you've learned and give you the confidence to implement authentication in real-world Flask applications. Remember, securing your app is essential in protecting user data and maintaining trust. Keep up the great work, and let's move on to the practice session!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.