Laravel Middleware Nedir ve Nasıl Kaydedilir?

## Middleware Nedir, Hangi Katmanda Çalışır? Laravel'de middleware, bir HTTP isteğinin uygulamaya ulaşması ile yanıtın kullanıcıya dönmesi arasındaki...

Laravel Middleware Nedir ve Nasıl Kaydedilir?

Middleware Nedir, Hangi Katmanda Çalışır?

Laravel'de middleware, bir HTTP isteğinin uygulamaya ulaşması ile yanıtın kullanıcıya dönmesi arasındaki ara katmanlardır. İstek uygulamaya girmeden önce çalışabilir, yanıt oluştuktan sonra da devreye girebilir. Kimlik doğrulama, yetkilendirme, CORS başlıkları, istek günlükleme, hız sınırlama gibi yatay kesen (cross-cutting) işler bu katmanda toplanır.

Bu rehber orta seviye geliştiriciler için yazıldı. Laravel 10 ve 11'deki middleware yapısı temel olarak aynıdır; Laravel 11'de uygulama iskeleti sadeleştiği için bazı kayıt noktaları değişti. Hangi sürümde olduğunuza göre ilgili notu dikkate alın. Kod örnekleri çerçevenin genel API'sine dayanır; kendi projenizde çalıştırmadan önce test etmeniz gerekir.

Middleware Yaşam Döngüsü

Bir middleware sınıfı tipik olarak tek bir handle metodu içerir:

public function handle(Request $request, Closure $next): Response
{
    // İstek buraya geldiğinde çalışır
    $response = $next($request);
    // Yanıt dönerken çalışır
    return $response;
}

$next($request) çağrısı, isteği bir sonraki katmana iletir. Bu çağrıdan önce yazdığınız kod istek yönünde, sonra yazdığınız kod yanıt yönünde çalışır. $next çağrılmazsa istek zincirde durur; bu durumda genellikle bir yönlendirme veya hata yanıtı döndürmeniz beklenir.

Katmanların sırası önemlidir. Bir middleware isteği reddederse, kendisinden sonraki katmanlar hiç çalışmaz.

Middleware Oluşturma

Artisan ile iskelet üretebilirsiniz:

php artisan make:middleware EnsureTokenIsValid

Üretilen sınıf app/Http/Middleware altına gelir. Basit bir örnek:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureTokenIsValid
{
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->input('token') !== 'beklenen-deger') {
            abort(403, 'Geçersiz token.');
        }

        return $next($request);
    }
}

Bu örnekte token parametresi sabit bir değerle karşılaştırılıyor. Gerçek projede sabit değer karşılaştırması yerine yapılandırmadan okunan bir değer veya güvenli bir karşılaştırma tercih edilmelidir. hash_equals gibi zamanlama saldırılarına dirençli fonksiyonlar, sır karşılaştırmalarında tercih edilir.

Middleware Kaydetme

Kayıt yeri Laravel sürümüne göre değişir.

Laravel 10 ve öncesi: app/Http/Kernel.php dosyasında üç dizi bulunur:

  • $middleware: Her istekte global çalışan katmanlar.
  • $middlewareGroups: web ve api gibi gruplar.
  • $middlewareAliases (eski adıyla $routeMiddleware): Rotalarda kısa adla çağrılan katmanlar.

Laravel 11 ve sonrası: Kernel.php kaldırıldı. Kayıtlar bootstrap/app.php içinde yapılır:

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'token' => \App\Http\Middleware\EnsureTokenIsValid::class,
    ]);
})

Global katman eklemek için $middleware->append(...), grup tanımlamak için $middleware->group(...) kullanılır. Rota seviyesinde kullanım her iki sürümde de aynıdır.

Rotalarda Kullanım

Tek bir rotaya bağlamak için:

Route::get('/profil', ProfileController::class)
    ->middleware('token');

Birden fazla katmanı sırayla bağlayabilirsiniz:

Route::get('/panel', PanelController::class)
    ->middleware(['auth', 'token']);

Grup içinde tanımlamak için:

Route::middleware(['auth'])->group(function () {
    Route::get('/ayarlar', SettingsController::class);
    Route::get('/faturalar', InvoiceController::class);
});

Sıralama, çalışma sırasını belirler. auth önce çalışırsa, kimliği doğrulanmamış istekler token katmanına hiç ulaşmaz. Bu, gereksiz işi baştan kesmek için istenen davranıştır.

Parametreli Middleware

Middleware'e rota tanımından parametre geçirebilirsiniz:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckRole
{
    public function handle(Request $request, Closure $next, string $role): Response
    {
        if (! $request->user()?->hasRole($role)) {
            abort(403);
        }

        return $next($request);
    }
}

Rota tarafında:

Route::get('/rapor', ReportController::class)
    ->middleware('role:editor');

Birden fazla parametre virgülle ayrılır ve handle imzasına sırayla eklenir: handle($request, $next, $param1, $param2).

İstek Sonrası Çalışan Katmanlar

Yanıt oluştuktan sonra müdahale etmek için handle içinde $next çağrısının dönüşünü kullanın:

public function handle(Request $request, Closure $next): Response
{
    $response = $next($request);
    $response->headers->set('X-Uygulama', 'laravel');

    return $response;
}

Laravel 11'de terminate metodu tanımlarsanız, yanıt kullanıcıya gönderildikten sonra çalışır. Bu, günlükleme veya arka plan işleri için uygundur; ancak yanıtı bu aşamada değiştiremezsiniz.

public function terminate(Request $request, Response $response): void
{
    // Yanıt gönderildikten sonra çalışır
}

terminate yalnızca FastCGI (php-fpm) gibi ortamlarda güvenilir şekilde tetiklenir; CLI veya bazı geliştirme sunucularında çağrılmayabilir.

Yaygın Hatalar

  • Sıralamayı yanlış kurmak. auth katmanından sonra gelen bir katman, kimliği doğrulanmamış isteklerde hiç çalışmaz. Katmanları "önce en genel, sonra en özel" mantığıyla dizin.
  • Global katmana ağır iş koymak. Her istekte çalışan bir katmana veritabanı sorgusu veya dış servis çağrısı eklemek, tüm uygulamanın gecikmesini artırır. Global katmanları hafif tutun.
  • $next çağrısını unutmak. Yan etki olmadan isteği durdurursanız, kullanıcı boş bir yanıt alır. Ya $next çağırın ya da açıkça bir yanıt döndürün.
  • Yanıtı terminate içinde değiştirmeye çalışmak. Yanıt gönderildikten sonra değişiklikler yansımaz.
  • web grubundan habersiz olmak. Oturum, CSRF ve çerez katmanları web grubunda tanımlıdır. API rotalarınızı web grubuna almak, CSRF doğrulaması gibi istenmeyen davranışlara yol açar.

Güvenlik Notları

Middleware güvenlik sınırı olarak kullanılabilir, ancak yanlış kurulumu sessiz açıklara yol açar.

  • Varsayılan olarak reddet. Yetkilendirme katmanlarında "izin verilenleri listele" yerine "yasaklananları listele" yaklaşımı, yeni rotalar eklendiğinde açık oluşma riskini azaltır.
  • Katman atlanabilir mi? Bir rotayı withoutMiddleware ile katmandan muaf tutabiliyorsunuz. Bu metodu yalnızca gerçekten gerekli olduğunda ve bilinçli olarak kullanın.
  • Sır karşılaştırmaları. Token, imza veya API anahtarı karşılaştırmalarında == veya === yerine hash_equals tercih edin.
  • Hata mesajları. 403 ve 401 yanıtlarında iç sistem detaylarını sızdırmayın. Kullanıcıya "yetkiniz yok" demek yeterlidir.
  • Sıra bağımlılığı. Bir katmanın güvenliği, kendisinden önce çalışan katmanların doğru çalıştığına bağlıdır. auth bozulursa, ona bağlı tüm yetkilendirme katmanları da etkisiz kalır.

Özet

Middleware, istek ve yanıt arasındaki kesişen işleri tek yerde toplamanızı sağlar. Kendi katmanınızı yazmak için make:middleware ile iskelet üretin, handle içinde isteği inceleyin, gerekirse reddedin ve $next ile zinciri sürdürün. Kayıt yerini sürüme göre seçin: Laravel 10 ve öncesinde Kernel.php, Laravel 11 ve sonrasında bootstrap/app.php. Katman sırasını bilinçli kurun, global katmanları hafif tutun ve yetkilendirme katmanlarında varsayılan olarak reddetme yaklaşımını benimseyin.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz