Laravel middleware ile isteklere ortak davranış eklemek
Laravel'de middleware nedir, nasıl yazılır ve kimlik doğrulama gibi kesişen ihtiyaçları nasıl tek yerde toplarım anlattım.
Bir Laravel projesinde belirli route’lara yalnızca giriş yapmış kullanıcıların erişebilmesini istiyorsunuz. Klasik yöntem her controller metoduna kontrol eklemek:
public function panel()
{
if (!Auth::check()) {
return redirect('/giris');
}
// ... asıl kod
}
Bu çalışır. Ama beş controller ve yirmi metod olduğunda aynı kodu yirmi yerde tekrarlıyorsunuz. Bir şeyi değiştirmeniz gerektiğinde yirmi yeri güncellemeniz gerekiyor.
Middleware, bu tür kesişen ihtiyaçları — kimlik doğrulama, yetkilendirme, istek kaydı, dil belirleme gibi her istekte tekrarlanan davranışları — tek bir yerde toplamanın yoludur. HTTP isteği ile controller arasına giriyor, isteği inceleyip değiştirebiliyor ya da tamamen durdurabiliyor.
Middleware nasıl çalışır?
Laravel’de bir istek geldiğinde middleware zincirinden geçer. Her middleware ya isteği bir sonraki adıma geçirir ya da yanıtı döndürerek zinciri keser. Bunu bir kapı dizisi gibi düşünebilirsiniz — her kapı isteği inceliyor.
Laravel 5 öntanımlı olarak birkaç middleware içeriyor: Authenticate (kimlik doğrulama), VerifyCsrfToken (CSRF koruması), RedirectIfAuthenticated (giriş yapmışsa yönlendir). Bunlar app/Http/Middleware/ altında.
Kendi middleware’inizi yazmak
php artisan make:middleware GirisKontrol
Bu komut app/Http/Middleware/GirisKontrol.php dosyasını oluşturuyor:
<?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);
}
}
handle metodu iki parametre alıyor: gelen istek ve $next adını verdiğimiz closure. $next($request) çağrısı isteği bir sonraki adıma geçiriyor. Koşul sağlanmadığında $next çağrılmıyor ve zincir kırılıyor.
Middleware’i kaydetmek
Yazılan middleware’i kullanabilmek için app/Http/Kernel.php içine kaydetmek gerekiyor. Bir kısa ad (alias) atıyorsunuz:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'giris' => \App\Http\Middleware\GirisKontrol::class,
// ...
];
Route’lara uygulamak
Tek bir route için:
Route::get('/panel', 'PanelController@index')->middleware('giris');
Birden fazla route için grup:
Route::group(['middleware' => 'giris'], function () {
Route::get('/panel', 'PanelController@index');
Route::get('/profil', 'ProfilController@index');
Route::get('/ayarlar', 'AyarlarController@index');
});
Bu gruba eklenen her route otomatik olarak giris middleware’inden geçiyor. Gruba yeni route eklemek için kontrol kodu yazmak gerekmiyor.
Controller constructor’da kullanmak
Middleware’i route yerine controller seviyesinde de belirtebiliyorsunuz:
class PanelController extends Controller
{
public function __construct()
{
$this->middleware('giris');
}
}
Yalnızca belirli metodlara uygulamak istiyorsanız:
$this->middleware('giris')->only(['index', 'goster']);
$this->middleware('giris')->except(['hakkinda']);
Controller constructor’da middleware tanımlamak ile route grubunda tanımlamak arasında ince bir fark var: controller seviyesindeki tanım, o controller’a ait tüm route’ları kapsıyor — route tanımında middleware’i unutsanız bile. Ama route grubuna yeni bir controller eklediğinizde middleware’i gruba dahil etmeyi hatırlamanız gerekiyor. Hangisinin daha güvenilir olduğu projenin yapısına göre değişiyor.
Yanıt sonrası middleware
Middleware yalnızca istek öncesinde değil, yanıt döndükten sonra da çalışabilir. Bunun için $next’i çağırdıktan sonra yanıtı işleyin:
public function handle($request, Closure $next)
{
$yanit = $next($request);
// Yanıta başlık ekle
$yanit->headers->set('X-Uygulama', 'benimsite');
return $yanit;
}
İstek günlüğü tutmak, yanıt başlıkları eklemek ya da performans ölçümü bu kalıbı kullanıyor.
Parametreli middleware
Middleware’e parametre geçirmek de mümkün. Örneğin rol kontrolü:
public function handle($request, Closure $next, $rol)
{
if (!$request->user()->hasRole($rol)) {
abort(403);
}
return $next($request);
}
Route’ta middleware('rol:admin') şeklinde kullanılıyor. Birden fazla parametre için virgülle ayırıyorsunuz: middleware('rol:admin,editor'). Handle metodunda bu parametreler ek argüman olarak geliyor.
Birden fazla middleware zincirlemek
Bir route’a birden fazla middleware uygulanabilir:
Route::get('/admin/panel', 'AdminController@index')
->middleware(['giris', 'rol:admin']);
Middleware’ler sırayla çalışıyor. giris kontrolü başarısız olursa rol:admin hiç çalışmıyor. Bu sıralama önemli: önce kimlik doğrulama, sonra yetkilendirme. Tersi durumda giriş yapmamış kullanıcı için $request->user() null dönebilir ve rol kontrolü hata üretebilir.
Middleware mantığını bir kez anlayınca her controller’da tekrarlanan kontrol kodlarını temizleme isteği uyanıyor. Kimlik doğrulama, dil belirleme, istek kayıt alma gibi davranışlar doğal olarak buraya taşınıyor. Controller metodları asıl işe odaklanabiliyor.