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:webveapigibi 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.
authkatmanı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ı
terminateiçinde değiştirmeye çalışmak. Yanıt gönderildikten sonra değişiklikler yansımaz. webgrubundan habersiz olmak. Oturum, CSRF ve çerez katmanlarıwebgrubunda tanımlıdır. API rotalarınızıwebgrubuna 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ı
withoutMiddlewareile 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===yerinehash_equalstercih 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.
authbozulursa, 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.