How to Use Middleware in Laravel Controllers
Wednesday, December 11, 2024
// 1 min read
Table of Contents
You can assign a middleware to a specific route, to add functionality like authentication, logging, or custom checks to specific actions. But it is also possible to do it inside a Controller class.
Attaching Middleware to Controller Actions
The middleware function was built in Laravel Controllers before version 11. Since version 11 you need to implement the HasMiddleware
interface to take advantage of this feature. If you want to implement the interface, your controller should have a static middleware method where you list the middlewares that should be applied to the controller actions. You can specify which middleware should be applied to which action.
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
use App\Http\Middleware\IsAdmin;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Routing\Controllers\HasMiddleware;
class PostController extends Controller implements HasMiddleware
{
/**
* Get the middleware that should be assigned to the controller.
*/
public static function middleware(): array
{
return [
'auth',
new Middleware(IsAdmin::class, only: ['store', 'create', 'edit', 'update', 'destroy']),
];
}
}
In this example, I applied the auth
middleware to my controller class. And separately the IsAdmin
middleware is applied to the selected actions only, so only the admin is allowed to create, update, or delete Posts.
You can create a middleware with the following artisan command:
php artisan make:middleware IsAdmin
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class IsAdmin
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
// Check if the user is unauthenticated, redirect to login
if (! $request->user()) {
return redirect()->route('login');
}
// If the user is not an admin, abort with a 403 error
if (! $request->user()->isAdmin()) {
abort(403, 'Unauthorized action.');
}
return $next($request);
}
}
Because my controller is a Resource Controller then in my web.php
routes files is enough to register a Resource Route:
Route::resource('posts', PostController::class);
I've written an entire article about how to use middleware in Laravel with the same middleware and routes as an example. The example above generates the same routes as these route definitions:
Route::middleware('auth')->group(function () {
Route::resource('posts', PostController::class)->only(['index', 'show']);
Route::resource('posts', PostController::class)->except(['index', 'show'])->middleware(IsAdmin::class);
});
Or these definitions:
Route::middleware('auth')->group(function () {
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::middleware([IsAdmin::class])->group(function () {
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
Route::get('/posts/{post}/edit', [PostController::class, 'edit'])->name('posts.edit');
Route::patch('/posts/{post}', [PostController::class, 'update'])->name('posts.update');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
});
});
You may also define a middleware as a closure instead of creating a middleware class:
public static function middleware(): array
{
return [
new Middleware(
function (Request $request, Closure $next) {
logger('User visited: ' . $request->path());
return $next($request);
},
only: ['show']
),
];
}
You can see the benefits of using the middleware static class inside a Controller, especially if you want to assign different middleware to different actions. If you want to know more about middlewares in general, read my detailed article HERE.
If you want to support my work, you can donate using the button below. Thank you!