Bir kullanıcı kendi yazısını düzenleyebilmeli ama bir başkasınınkini değil; bir editör yorumları silebilmeli ama sıradan üye silememeli. Laravel yetkilendirme tam olarak bu tür kuralları, iş mantığınızı kirletmeden tek bir yerde toplamanızı sağlar. Bu rehberde Policy ve Gate'in ne zaman kullanılacağını, model bazlı erişim kontrolünü nasıl kuracağınızı ve bunu controller, Blade ve API katmanlarında nasıl uygulayacağınızı adım adım göreceğiz.
Kimlik doğrulama ile yetkilendirme aynı şey değil
Önce iki kavramı net ayıralım. Kimlik doğrulama (authentication) "sen kimsin?" sorusunu yanıtlar; giriş ekranı, parola ve oturum bununla ilgilenir. Yetkilendirme (authorization) ise "bunu yapmaya iznin var mı?" sorusunu yanıtlar. Bir kullanıcı giriş yapmış olabilir ama yine de başka bir kullanıcının faturasını görmeye yetkisi olmayabilir. Laravel'de yetkilendirmenin iki ana aracı vardır: Gate ve Policy.
Gate ne zaman, Policy ne zaman?
İkisi de aynı motoru kullanır ama kullanım alanları farklıdır:
- Gate — belirli bir modele bağlı olmayan, basit ve kapsayıcı izinler için idealdir. Örneğin "yönetim paneline erişim" veya "site ayarlarını değiştirme". Closure tabanlıdır ve genelde
AppServiceProvideriçinde tanımlanır. - Policy — tek bir Eloquent modeli etrafında dönen izinleri (görüntüleme, oluşturma, güncelleme, silme) bir sınıfta toplar.
Post,Invoice,Projectgibi modellerin CRUD yetkileri için doğru seçimdir.
Pratik kural: izin bir model satırına bağlıysa Policy, değilse Gate kullanın.
Gate ile basit bir izin tanımlamak
Modele bağlı olmayan bir kuralı doğrudan bir Gate olarak tanımlayabilirsiniz. Closure'ın ilk parametresi her zaman oturum açmış kullanıcıdır:
use Illuminate\Support\Facades\Gate;
use App\Models\User;
public function boot(): void
{
Gate::define('access-admin', function (User $user) {
return $user->is_admin;
});
}
Kontrol etmek için Gate::allows() veya Gate::denies() kullanırsınız:
if (Gate::allows('access-admin')) {
// panel içeriğini göster
}
Model bazlı erişim kontrolü için Policy oluşturmak
Asıl güç Policy'lerde. Bir model için Policy üretmek tek komut:
php artisan make:policy PostPolicy --model=Post
--model bayrağı, view, create, update, delete gibi standart metotları hazır iskeletle oluşturur. İçini iş kuralınıza göre doldurursunuz:
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}
Laravel 11 ve sonrasında Policy'ler, isimlendirme kuralına uyduğunuz sürece (App\Models\Post → App\Policies\PostPolicy) otomatik keşfedilir; ayrıca kayıt yapmanız gerekmez. Farklı bir eşleme isterseniz Gate::policy(Post::class, PostPolicy::class) ile elle bağlayabilirsiniz.
Policy'yi controller'da kullanmak
Controller içinde en temiz yöntem authorize metodudur. Kural sağlanmazsa Laravel otomatik olarak 403 yanıtı fırlatır:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$post->update($request->validated());
return redirect()->route('posts.show', $post);
}
Tüm CRUD metotlarını tek satırda eşlemek isterseniz, controller'ın yapıcısında authorizeResource kullanabilirsiniz; bu, resource controller metotlarını Policy metotlarına otomatik bağlar:
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
Blade ve API katmanında uygulamak
Yetkilendirme sadece controller'da kalmaz. Blade'de bir butonu yetkisi olmayan kullanıcıya göstermemek için @can direktifini kullanın:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Düzenle</a>
@endcan
API ve form isteklerinde route'ları topluca korumak için can middleware'i işinizi görür:
Route::put('/posts/{post}', [PostController::class, 'update'])
->middleware('can:update,post');
Bir kullanıcı nesnesi üzerinden de kontrol yapabilirsiniz: $user->can('update', $post). Bu, JSON yanıtında "düzenleyebilir mi?" bilgisini frontend'e göndermek için kullanışlıdır.
before kancası ve yaygın hatalar
Yöneticilerin her şeyi yapabilmesini istiyorsanız, Policy'ye bir before metodu ekleyin. Bu metot diğer tüm kontrollerden önce çalışır ve true döndürürse gerisini atlar:
public function before(User $user, string $ability): ?bool
{
return $user->is_admin ? true : null;
}
Burada null döndürmek kritik: false döndürürseniz diğer metotlar hiç çalışmaz ve admin olmayan herkesi engellersiniz. Diğer sık hatalar: misafir (giriş yapmamış) kullanıcılarda parametreyi ?User $user olarak nullable yapmayı unutmak, ve authorize ile can arasındaki farkı karıştırmak — ilki istisna fırlatır, ikincisi boolean döner.
Sık Sorulan Sorular
Policy mi Gate mi kullanmalıyım?
İzin belirli bir Eloquent modelinin satırına bağlıysa (örneğin "bu yazıyı düzenle") Policy kullanın. Modele bağlı olmayan genel izinler için (örneğin "panele eriş") Gate daha sade kalır.
Policy'leri elle kaydetmem gerekir mi?
Laravel 11+ için hayır; isimlendirme kuralına uyduğunuz sürece otomatik keşfedilir. Yalnızca farklı bir model-policy eşlemesi gerekiyorsa Gate::policy() ile elle bağlamanız yeterli.
403 yerine özel bir mesaj döndürebilir miyim?
Evet. Policy metodunda Illuminate\Auth\Access\Response::deny('mesaj') döndürerek özel hata metni ve durum kodu verebilir, true yerine Response::allow() kullanabilirsiniz.
Yetkilendirmeyi baştan doğru kurmak, projenizi büyüdükçe güvende tutar. Laravel projenizde erişim kontrolünü temiz ve sürdürülebilir biçimde kurmak için benimle iletişime geçin.