Laravel – 5.0 And Middlewares
In Laravel-5.0 we can now use Middlewares
instead of filters
such as before
but Middlewares
are not new and was available in Laravel-4
as well. In version-4
if we need a Middleware
then we may use a custom Middleware
by creating a class
and implementing the HttpKernelInterface interface
, for example in laravel-4
we can create a class
like following one as a custom Middleware
:
app = $app; } public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { // 1) Modify incoming request if needed and chain the app handler to get the response $response = $this->app->handle($request, $type, $catch); // 2) Modify the response if needed and return the response return $response; } }
Then, from the app/start/global.php
file we can register the Middleware
using following code or we may create a Service Provider
as well but not necessary:
App::middleware('Middleware\MyMiddleWare');
To unregister a Middlewares
we can use something like this:
App::forgetMiddleware('Middleware\MyMiddleWare');
Actually a Middleware
is one kind of filter and each one calls the Middleware
that is right below it because Middlewares
are constructed as a stack, which looks something like this:
private 'middlewares' => array (size=6) 0 => object(Illuminate\Cookie\Guard)[93] protected 'app' => object(Illuminate\Cookie\Queue)[92] ... 1 => object(Illuminate\Cookie\Queue)[92] protected 'app' => object(Illuminate\Session\Middleware)[91] ... 2 => object(Illuminate\Session\Middleware)[91] protected 'app' => object(Illuminate\Http\FrameGuard)[89] ... 3 => object(Illuminate\Http\FrameGuard)[89] protected 'app' => object(Middleware\MyMiddleWare)[90] ... 4 => object(Middleware\MyMiddleWare)[90] protected 'app' => object(Illuminate\Foundation\Application)[2] ... 5 => object(Illuminate\Foundation\Application)[2] ...
If you check the code in Illuminate\Foundation\Application.php
file then you can see something like this:
public function run(SymfonyRequest $request = null) { $request = $request ?: $this['request']; // Middlewares are called from here, start from the first one in the stack $response = with($stack = $this->getStackedClient())->handle($request); $response->send(); $stack->terminate($request, $response); }
Since each Middleware
has a handle
method and in the handle
method of each one there is a call for the Middleware
it’s below one using something like this:
$this->app->handle($request, $type, $catch);
So, the framework calls the handle
on top but the top one gets executed at last, anyways, it was just a recap. So, what’s new in Laravel-5.0
with Middleware
exactly?
Well, in Laravel-5.0
it replaces the filters
, actually we can still use the filters
but Middlewares
are exclusively being used to replace old before filters
such as auth
, auth.basic
, csrf
etc and it’s a recommended way in laravel-5.0
. In the Laracast Discussion Forum
there is a comment by taylor Otwell
as given below:
To clarify, filters are still available to use and assign to routes, because I don’t want to break people’s filter setups. However, going forward, we will be encouraging middlewares as they have a consistent signature across all types of requests.
So, let’s dig in to Laravel-5.0 Middleware
now:
In Laravel-5.0
we have a new directory structure and in the app/Http
folder there is a Middleware
folder available which contains following files by default:
AuthMiddleware.php BasicAuthMiddleware.php CsrfMiddleware.php GuestMiddleware.php MaintenanceMiddleware.php
These are being used as Middlewars
as a replacement of filters, for example we know that we can use a route before filter
like:
$router->post( 'user/register', [ 'uses' => 'UserController@register', 'as' => 'user.add', 'before' => 'auth' ]);
This is not new and we know what it does, simply it just calls the auth filter
before our register
method gets called so we can check if the user is logged in or not, very simple and common task. It requires a route filter
declaration as well but I’m just omitting this part here. So, instead of a before filter
now a Middleware
is being used and that Middleware
class is available in the app/Http/Middleware
directory; which is AuthMiddleware.php
and it has the handle
method to check whether the use is logged in or not. The code looks like this:
public function handle($request, Closure $next) { if ($this->auth->guest()) { if ($request->ajax()) { return $this->response->make('Unauthorized', 401); } else { return $this->response->redirectGuest('auth/login'); } } return $next($request); }
Also in app/providers/AppServiceProviders.php
file there is a protected $middleware
property available which looks like this:
protected $middleware = [ 'auth' => 'App\Http\Middleware\AuthMiddleware', 'auth.basic' => 'App\Http\Middleware\BasicAuthMiddleware', 'csrf' => 'App\Http\Middleware\CsrfMiddleware', 'guest' => 'App\Http\Middleware\GuestMiddleware', ];
This holds the Middlewares
that are available to be used in our application but none of these are being called by default, it means that, if we don’t use them in out application then these won’t be called by the framework. Here, the array
keys are aliases
for each Middleware
and we can use them, for example, if we want to use the auth
for checking the he user is logged in or not then we may use it in our route
like this:
$router->get('users', [ 'uses' => 'UserController@index', 'as' => 'users.list', 'middleware' => 'auth' ]);
That’s it. Now, the handle
method of AuthMiddleware
class will be called on this route before it get’s dispatched. So, how can we create our own Middleware
instead of a filter, for example, if we want to create a route
filter for checking user permission on specific routes, in an ACL
based application then in older version we could have used a route
like this:
Route::get('user/register', array( 'before' => 'auth', 'uses' => 'UserController@index', 'as' => 'users.list' ));
In laravel-5.0
we can now use a Middleware
instead and to create a Middleware
we can use the artisan
command line tool that Laravel
provides and the command is as given below:
php artisan make:middleware PermissionMiddleware
This will create a class in app/Http/Middleware
directory, something like this:
So, now we just need to write code in the
handle
method and finally we need to add thisMiddleware
in the$middleware
array inapp/Providers/AppServiceProvider.php
file, which may look like this after adding the entry:protected $middleware = [ 'auth' => 'App\Http\Middleware\AuthMiddleware', 'auth.basic' => 'App\Http\Middleware\BasicAuthMiddleware', 'csrf' => 'App\Http\Middleware\CsrfMiddleware', 'guest' => 'App\Http\Middleware\GuestMiddleware', 'permission' => 'App\Http\Middleware\PermissionMiddleware', ];That's it. Now let's write some code for the
handle
method as given below:public function handle($request, Closure $next) { if($this->hasPermission()) { return $next(); } return redirect('/'); }This is very simple, we are just checking if the user has permission using
$this->hasPermission()
, imagine that we have declared thehasPermission
method in this class which does the checking and returnsTRUE
orFALSE
and if our condition satisfies (User has the permission) then using$next()
we are actually calling aclosure
and this is the anotherMiddleware
below it on the stack. So, it's important to call the$next()
from eachhandle
method in theMiddleware
class otherwise we won't get the expected result. So that's it. Now, we can use it in aroute
using something like this:$router->get('users/register', [ 'uses' => 'UserController@index', 'as' => 'users.list', 'middleware' => 'permission' ]);Remember that, we can still use the
before filter
for this, check the documentation on Laravel website for details but this is more advanced and recommended way inLaravel-5.0
.