Skip to content
Muhammet Şafak
tr
Framework & Library 4 min read

Adding shared behavior to requests with Laravel middleware

What middleware is in Laravel, how to write it, and how to centralize cross-cutting concerns like authentication in one place.


You want only authenticated users to access certain routes in a Laravel project. The classic approach is adding a check to every controller method:

public function panel()
{
    if (!Auth::check()) {
        return redirect('/giris');
    }

    // ... actual code
}

This works. But once you have five controllers and twenty methods, you are repeating the same code in twenty places. When something needs to change, you need to update all twenty spots.

Middleware is the way to centralize these kinds of cross-cutting concerns — behaviors that repeat on every request, like authentication, authorization, request logging, and locale detection — into a single place. It sits between the HTTP request and the controller, and it can inspect and modify the request, or stop it entirely.

How middleware works

When a request arrives in Laravel, it passes through a middleware chain. Each middleware either passes the request to the next step or returns a response to break the chain. Think of it as a series of gates — each gate inspects the request.

Laravel 5 ships with several built-in middleware: Authenticate (authentication), VerifyCsrfToken (CSRF protection), RedirectIfAuthenticated (redirect if already logged in). These live under app/Http/Middleware/.

Writing your own middleware

php artisan make:middleware GirisKontrol

This command creates app/Http/Middleware/GirisKontrol.php:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class GirisKontrol
{
    public function handle($request, Closure $next)
    {
        if (!Auth::check()) {
            return redirect('/giris');
        }

        return $next($request);
    }
}

The handle method takes two parameters: the incoming request and a closure we call $next. Calling $next($request) passes the request to the next step. When the condition is not met, $next is never called and the chain is broken.

Registering middleware

To use the middleware you have written, you need to register it in app/Http/Kernel.php by assigning it a short alias:

protected $routeMiddleware = [
    'auth'    => \App\Http\Middleware\Authenticate::class,
    'giris'   => \App\Http\Middleware\GirisKontrol::class,
    // ...
];

Applying it to routes

For a single route:

Route::get('/panel', 'PanelController@index')->middleware('giris');

For multiple routes using a group:

Route::group(['middleware' => 'giris'], function () {
    Route::get('/panel',    'PanelController@index');
    Route::get('/profil',   'ProfilController@index');
    Route::get('/ayarlar',  'AyarlarController@index');
});

Every route added to this group automatically passes through the giris middleware. You do not need to write any control code when adding a new route to the group.

Using middleware in a controller constructor

You can also specify middleware at the controller level rather than in the route:

class PanelController extends Controller
{
    public function __construct()
    {
        $this->middleware('giris');
    }
}

If you want to apply it only to specific methods:

$this->middleware('giris')->only(['index', 'goster']);
$this->middleware('giris')->except(['hakkinda']);

There is a subtle difference between defining middleware in a controller constructor versus in a route group: controller-level middleware covers all routes belonging to that controller — even if you forget to add the middleware in the route definition. But when you add a new controller to a route group, you need to remember to include it in the group. Which approach is more reliable depends on the structure of your project.

After-response middleware

Middleware can run not only before the request is handled, but also after the response has been sent. To do this, process the response after calling $next:

public function handle($request, Closure $next)
{
    $yanit = $next($request);

    // Add a header to the response
    $yanit->headers->set('X-Uygulama', 'benimsite');

    return $yanit;
}

Request logging, adding response headers, and performance measurement all use this pattern.

Middleware with parameters

You can also pass parameters to middleware. For example, a role check:

public function handle($request, Closure $next, $rol)
{
    if (!$request->user()->hasRole($rol)) {
        abort(403);
    }

    return $next($request);
}

It is used on a route as middleware('rol:admin'). For multiple parameters, separate them with commas: middleware('rol:admin,editor'). In the handle method, these parameters arrive as additional arguments.

Chaining multiple middleware

You can apply more than one middleware to a route:

Route::get('/admin/panel', 'AdminController@index')
     ->middleware(['giris', 'rol:admin']);

Middleware runs in order. If the giris check fails, rol:admin never runs. This ordering matters: authentication first, then authorization. The other way around, $request->user() could return null for an unauthenticated user and the role check would throw an error.

Once you internalize the middleware concept, you naturally want to clean up all the repeated control code scattered across controllers. Authentication, locale detection, request logging — these behaviors belong here. Controller methods can then focus on the actual work.

Tags: #Laravel
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

Related Posts

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind