Article
Laravel: Middlewares
Today we'll see a key part of all web projects : middlewares sometimes called filters. Easy to understand for senior developers, they are a real difficulty for beginners.
In this article, we introduce middlewares and their use into Laravel. I'm writing a compendium on the Laravel framework introducing its functionning. I notably explaining the requests life cycle et how are middlewares included into it.
What's a middleware ?
To make things simple, these are functions allowing to improve or check a request before it gets to your controller.
Many middlewares are included by default in Laravel, like auth
allowing access to a route only for the requests linked to a logged in user.
Default Middlewares
Laravel includes the following middlewares in each new project :
- Authenticate : return a 401 if the request doesn't contain an Authorization
- CheckForMaintenanceMode : If the app is in maintenance mode, check if the IP or the request is allowed to execute despite the maintenance
- EncryptCookies : Encrypt the cookies
- RedirectIfAuthenticated : Redirect on the specified route like Home if the user is logged in
- TrimStrings : Trim every field of the request body
- TrustProxies : List all proxies that send requests to your server
- VerifyCsrfToken : check the Csrf token given by the request
The framework itself contains many more:
- AuthenticateWithBasicAuth
- Authorize
- EnsureEmailsVerified
- RequiredPassword
- AddQueuedCookiesToResponse
- ConvertEmptyStringToNull
- TransformRequest
- ValidatePostSize
- CheckResponseForModifications
- FrameGuard
- SetCacheHeadersd
- SubstituteBindings
- ThrottleRequests
- ThrottleRequestsWithRedis
- ValidateSignature
- AuthenticateSession
- StartSession
- ShareErrorsFromSession
Create your own middleware
With artisan, it's possible to create your own middleware with the following command :
php artisan make:middleware CheckAge
For Lumen, you can directly create the file in app/Http/Middleware
.
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAge {
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next * @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect(‘home’);
}
}
}
This class uses a handle
function which will be call by the framework when you will use your middleware. The most important is the call the the callback next
who allows to keep the request going.
It is possible to add parameters to the handle
function that you can define when you call it.
<?php
namespace App\Http\Middleware;
use Closure;
class CheckRole {
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect…
}
}
}
Once your middleware is created, we just have to register it for it to be recognized by Laravel.
Register your middleware
Depending of your needs, there are many ways to register your middleware: - for the whole app - for a single route - in a middleware group.
Register your middleware for the whole app
For it to launch at each request, you need to register the $middleware
attribute into the app/Http/Kernel.php
file.
Register a middleware for a single route
The middleware's list you can use for your routes or routes groupes is located in the $routeMiddleware
attribute from the App\Http\Kernel
class. It can be shaped like an associative array where the key is a string which will be used as an identifier ans the value is your middleware class.
Then we can use it directly into our routes.
Route::get('admin/profile', "MyController@fonction")->middleware('auth');
It is possible to use the class name instead of the array's key to benefit from the autocomplete.
Route::get('admin/profile', "MyController@fonction")->middleware(CheckAge::class);
It is also possible to register multiple middlewares for a single route.
Route::get('/', function () {})->middleware('first', 'second');
Finally, it is possible to block a specific middleware execution from a group for one of its routes.
Route::middleware([CheckAge::class])->group(function () {
Route::get(‘/’, function () {});
Route::get('admin/profile', function () {})->withoutMiddleware([CheckAge::class]);
});
Register a middleware for a request group
When you use multiple middlewares together, it is possible to create a group into the $middlewareGroups
property. You will then only need to call this group to use all its middlewares.
This is the default use of Laravel with the web
and api
groups.
/**
* The application's route middleware groups.
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1','auth:api',
],
];
Pass parameters to your middleware
You pass parameters to your middleware with a :
after the middleware identifier. If there are many arguments, we separate them with ,
.
Route::put('post/{id}', function ($id) {})->middleware('role:editor');