Don’t Get Hacked: How to Use Laravel Middleware to Secure Your App Like a Pro
Mastering Authentication and Authorization in Laravel
Middleware in Laravel acts as a gatekeeper, allowing or denying access to specific routes based on the user’s authentication status or other conditions. This article will cover how to limit access to certain pages/resources using middleware in Laravel and various types of middleware available in Laravel.
Types of Middleware
- Global Middleware: Global middleware runs on every request, regardless of the URI. Examples include the
auth
middleware, which checks if the user is logged in. - Route Middleware: Route middleware is specific to a particular route or group of routes. Examples include
authenticated
middleware, which we will discuss later in this article. - Controller Middleware: Controller middleware is specific to a particular controller or group of controllers. This type of middleware can limit access to specific actions within a controller.
Creating a Custom Middleware
- Use the command
php artisan make:middleware Authenticated
to create a new middleware file in theapp/Http/Middleware
directory. - In the handle method of this middleware, you can add code to check whether the user is authenticated.
- The middleware will access the requested page if the user is authenticated. Conversely, if not authorized, the middleware will redirect the user to the login page.
Assigning Middleware to Routes
- You can assign this middleware to a group of routes by adding the
middleware
key in the group in yourweb.php
orapi.php
file.
Route::middleware(['authenticated'])->group(function () {
Route::get('/secret-page', function () {
// Only authenticated users can access this page
});
});
You can also use the built-in auth
middleware, included with Laravel, to limit access to specific routes based on whether the user is logged in.
Roles and Permissions
- Laravel also provides roles and permission-based guard to limit access to certain pages based on user role or permission.
- It can be done using packages like
spatie/laravel-permission
orzizaco/entrust
. - These packages provide additional functionalities like creating and managing user roles and permissions.
Custom Authentication and Authorization
- Laravel’s built-in authentication and authorisation features are robust and easy to use, but sometimes you may need to customise them to fit your application’s specific needs.
- You can create your authentication and authorisation middleware to handle these custom requirements.
- For example, you can create custom middleware to check if a user has a specific role or permission before allowing access to a route.
Testing Middleware
- It is essential to test your middleware and routes to ensure they are working as expected.
- You can use Laravel’s built-in testing tools to write test cases for your middleware and routes.
- For example, you can write test cases to check if a user is redirected to the login page when trying to access a protected route without being authenticated.
Alternative methods
Using Controller Methods
Instead of using middleware, you can create a method within a controller that checks whether the user is authenticated. The controller can redirect the user to the login page if the user is not authenticated. You can then call this method at the beginning of any actions that need to be protected.
For example, you can create a CheckAuth
trait that contains a check
method that checks if the user is logged in. You can then use this trait in any controller that needs to protect certain actions:
trait CheckAuth {
public function check()
{
if (!Auth::check()) {
return redirect()->route('login');
}
}
}
Then in your controller, you can use this trait
class SecretPageController extends Controller
{
use CheckAuth;
public function index()
{
$this->check();
// Only authenticated users can access this page
}
}
Using Gates and Policies
Laravel’s authorisation gates and policies allow you to define fine-grained access controls for your application’s resources. For example, you can use them to check if a user is authorised to perform a specific action on a resource and limit access accordingly.
For example, you can create a PostPolicy
that defines a view
method that checks if a user is authorised to view a post.
class PostPolicy
{
public function view(User $user, Post $post)
{
return $user->isAdmin() || $post->isPublished();
}
}
Then in your controller, you can use the authorise
method to check if a user is authorised to view a post:
class PostController extends Controller
{
public function show(Post $post)
{
$this->authorize('view', $post);
// Only authorised users can view this post
}
}
Using JWT (JSON Web Tokens)
JWT(JSON Web Tokens) is a popular method of stateless authentication. It can be used for both web and API projects.
A JWT is a JSON object that contains claims. Claims are statements about an entity (typically, the user) and additional metadata. For example, once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources permitted with that token.
For example, on login, the server will create a JWT and return it to the client
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODAwMFwvYXBpXC9sb2dpbiIsImlhdCI6MTU5NzY4MzY4NiwiZXhwIjoxNTk3Njg3Mjg2LCJuYmYiOjE1OTc2ODM2ODYsImp0aSI6IjhXZnJtV1lNV1JjbHJnIiwic3ViIjoiIiwicHJ2IjoiMjNiZDVjODk0OWY2"
}
Once the client receives the JWT, it will store it and include it in the headers of all subsequent requests to the server.
The server can then use middleware to check the JWT on each request and verify that the token is valid and has not expired. The server will allow the request to continue if the ticket is valid. If the token is invalid or has expired, the server will return a 401 Unauthorized response.
Here’s an example of how you can use the tymon/jwt-auth
package to handle JWT authentication in a Laravel application:
- Install the package by running
composer require tymon/jwt-auth
- Add the
JWTAuth
facade and theJWTAuth
middleware to yourconfig/app.php
file. - Run the command
php artisan jwt: secret
to generate a JWT secret key. - In the login method of your
AuthController
, you can use theJWTAuth
facade to generate a JWT token and return it to the client upon successful login.
public function login(Request $request)
{
// validate login credentials
$credentials = $request->only('email', 'password');
if (!$token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return response()->json(compact('token'));
}
In the api.php
or web.php
file, you can use the jwt.auth
middleware to protect routes that require authentication.
Route::middleware(['jwt.auth'])->group(function () {
Route::get('/secret-page', function () {
// Only authenticated users with valid JWT can access this page
});
});
It’s important to note that JWT is a stateless method, so you must handle the logout and token refresh yourself. However, JWT is a good choice for API projects requiring scalability and stateless structure.
Performance and Scalability
- As your application grows, it is essential to consider the performance and scalability of your middleware.
- You can optimise the performance of your middleware by keeping the handle method short and straightforward and moving complex logic to other classes or controllers.
- You can also use caching techniques to speed up the execution of your middleware, mainly when dealing with large amounts of data or complex calculations.
- When dealing with high traffic, you may consider using load balancing or horizontal scaling to distribute the load across multiple servers.
- It’s also essential to monitor your application’s performance and make adjustments to ensure smooth operation during peak traffic.
Conclusion
This article has covered how to limit access to certain pages using middleware in Laravel. We also discussed the different types of middleware available in Laravel, such as global middleware, route middleware, and controller middleware and when to use them. Additionally, we covered how to implement custom authentication and authorisation in Laravel, test middleware and routes, and optimise middleware performance and scalability. Always keep in mind the best practices while working with middleware in Laravel to ensure your application's security, performance, and scalability.