In this lesson, we will learn how to protect parts of our To-Do List application using middleware in Express.js
. Middleware acts as checkpoints that control access to different routes. By the end of this lesson, you'll understand how to use middleware to enhance the security of your application, much like an office building's security system determines who can access different floors.
In this lesson, you'll learn:
- What middleware is and why it's important.
- How to set up middleware in
Express.js
. - How to use middleware to protect routes.
- How to manage sessions for user authentication.
Middleware in Express.js
is a series of small programs that handle requests and responses. Imagine middleware as security checkpoints in a building; each checkpoint ensures only authorized individuals can proceed to certain areas.
Middleware can:
- Execute any code.
- Modify request and response objects.
- End the request-response cycle.
- Move to the next middleware function.
Middleware ensures your application is secure and functions properly by controlling the flow of requests and responses.
Let's set up our Express.js
application and connect to MongoDB
. This is essential for a running server and a database to store user information.
JavaScript1const express = require('express'); 2const mongoose = require('mongoose'); 3const session = require('express-session'); 4 5const app = express(); 6const PORT = 3000; 7 8// Connect to MongoDB 9mongoose.connect('mongodb://127.0.0.1:27017/todo-app', { 10 useNewUrlParser: true, 11 useUnifiedTopology: true 12});
Here, we import the necessary libraries, initialize an Express.js
application, and connect to a MongoDB
database named todo-app
. Connecting to MongoDB
is crucial for storing user data and managing user authentication.
Sessions help track user information as they navigate through the app, similar to how an office maintains visitor logs.
JavaScript1// Middleware for sessions 2app.use(session({ 3 secret: 'your-secret-key', 4 resave: false, 5 saveUninitialized: true 6}));
In this step, we use the express-session
middleware to manage sessions. We configure the session with a secret
key to sign the session ID cookie, which helps prevent tampering. The resave
option, set to false
, ensures the session is not saved back to the session store unless it has been modified. The saveUninitialized
option, set to true
, saves new but unmodified sessions to the store. This setup allows the application to maintain state across multiple requests, essential for tracking logged-in users.
Let’s create our custom middleware function to check if a user is logged in. This function will act as a security checkpoint to protect sensitive routes.
JavaScript1// Middleware to check if the user is logged in 2const authenticateUser = (req, res, next) => { 3 if (!req.session.user) return res.status(401).json({ message: 'Access denied' }); 4 next(); 5};
Here, we define a middleware function called authenticateUser
. The function checks if req.session.user
exists, which stores data specific to the logged-in user. If the user is not logged in, it returns a 401 status (Unauthorized) with an "Access denied" message. If the user is logged in, it calls the next()
function to proceed.
We need a route to handle user login. This route will check the user's credentials and create a session upon successful login.
JavaScript1// Simple user database simulation 2const users = { 3 'testuser': 'testpassword' 4}; 5 6// Login route 7app.post('/login', (req, res) => { 8 const { username, password } = req.body; // req.body contains the data sent in the request 9 if (users[username] && users[username] === password) { 10 req.session.user = username; // Save user in session 11 res.json({ message: 'Login successful' }); 12 } else { 13 res.status(401).json({ message: 'Invalid username or password' }); 14 } 15});
In this part, we simulate a simple user database with an object. The /login
route accepts a POST request with username
and password
. If the credentials match, it saves the user in the session and returns a success message. Otherwise, it returns an error message. Handling user login is essential for managing access to your application, which will allow us to protect specific routes.
Let's create a protected route that only logged-in users can access. We'll use our authenticateUser
middleware to guard this route.
JavaScript1// Route to handle protected route 2app.get('/protected', authenticateUser, (req, res) => { 3 res.send('This is a protected route'); 4});
Here, we create a protected route /protected
and use the authenticateUser
middleware before the route handler. If the user is authenticated, it shows the message "This is a protected route"; otherwise, it returns "Access denied". Protecting routes ensures only authorized users can access sensitive parts of your application.
In this lesson, we learned how to protect routes in an Express.js
application using middleware. We set up sessions, created an authenticateUser
middleware, and handled user login to manage access to a protected route.
Practice exercises are essential to reinforce what you've learned. By protecting routes, you ensure that only authorized users can access sensitive parts of your application, making it more secure. Now, let's practice.