Laravel'de Policy ve Gate ile Gelişmiş Yetkilendirme
Authentication (kimlik doğrulama) "kim bu?" sorusunu, Authorization (yetkilendirme) "bu kişi bunu yapabilir mi?" sorusunu yanıtlar. Laravel her ikisi için de güçlü araçlar sunar. Bu yazıda Gate ve Policy mekanizmalarıyla yetkilendirme sistemini nasıl kuracağımızı göreceğiz.
Gate: Basit Yetkilendirme Kontrolleri
Gate'ler tekil eylem bazlı yetkilendirme kontrolü sağlar. Genellikle AuthServiceProvider veya AppServiceProvider içinde tanımlanır:
use Illuminate\Support\Facades\Gate;
use App\Models\User;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
Gate::define('manage-users', function (User $user) {
return $user->role === 'admin';
});
Gate::define('manage-settings', function (User $user) {
return in_array($user->role, ['admin', 'editor']);
});
}
}
Gate Kullanımı
Controller'da:
public function index()
{
if (Gate::denies('manage-users')) {
abort(403, 'Bu işlemi gerçekleştirme yetkiniz yok.');
}
return view('admin.users.index');
}
// veya daha kısa
public function index()
{
Gate::authorize('manage-users');
return view('admin.users.index');
}
Blade template'de:
@can('manage-users')
<a href="{{ route('admin.users') }}">Kullanıcı Yönetimi</a>
@endcan
@cannot('manage-users')
<p class="text-gray-400">Bu alana erişim yetkiniz yok.</p>
@endcannot
Gate::before ve Gate::after
Süper admin gibi kullanıcılar için tüm kontrolleri bypass etme:
Gate::before(function (User $user, string $ability) {
if ($user->role === 'super-admin') {
return true; // Her şeye izin ver
}
});
Policy: Model Bazlı Yetkilendirme
Policy, belirli bir model üzerindeki yetkilendirme işlemlerini organize bir şekilde tanımlar. Daha büyük projelerde Gate'lerden çok daha düzenli bir yapı sağlar.
Policy Oluşturma
php artisan make:policy PostPolicy --model=Post
namespace App\Policies;
use App\Models\User;
use App\Models\Post;
class PostPolicy
{
public function viewAny(User $user): bool
{
return true; // Herkes listeyi görebilir
}
public function view(User $user, Post $post): bool
{
return true; // Herkes okuyabilir
}
public function create(User $user): bool
{
return $user->role !== 'banned';
}
public function update(User $user, Post $post): bool
{
return $user->id === $post->author_id;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->author_id || $user->role === 'admin';
}
}
Policy'yi Kaydetme
AuthServiceProvider veya AppServiceProvider:
use App\Models\Post;
use App\Policies\PostPolicy;
protected $policies = [
Post::class => PostPolicy::class,
];
public function boot(): void
{
$this->registerPolicies();
}
Laravel 11+ ile auto-discovery aktifse ve isimlendirme convention'ına uyarsanız (PostPolicy → Post modeli) otomatik bulunur.
Policy Kullanımı
Controller'da:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$post->update($request->validated());
return redirect()->route('posts.show', $post)
->with('success', 'Yazı güncellendi.');
}
public function destroy(Post $post)
{
$this->authorize('delete', $post);
$post->delete();
return redirect()->route('posts.index')
->with('success', 'Yazı silindi.');
}
Blade template'de:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}"
class="text-blue-600 hover:text-blue-800">
Düzenle
</a>
@endcan
@can('delete', $post)
<form action="{{ route('posts.destroy', $post) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-800">
Sil
</button>
</form>
@endcan
Middleware ile Rol Bazlı Yetkilendirme
Custom middleware ile:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class RoleMiddleware
{
public function handle(Request $request, Closure $next, string ...$roles)
{
if (!in_array($request->user()->role, $roles)) {
abort(403, 'Yetkiniz yok.');
}
return $next($request);
}
}
Route'larda kullanım:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role' => \App\Http\Middleware\RoleMiddleware::class,
]);
})
// routes/web.php
Route::middleware('role:admin,editor')->group(function () {
Route::get('/admin/dashboard', [DashboardController::class, 'index']);
});
Route::middleware('role:admin')->group(function () {
Route::resource('/admin/users', UserController::class);
});
Gate vs Policy: Hangisini Kullanmalı?
| Durum | Tercih |
|---|---|
| Basit yetki kontrolü (sayfa erişimi) | Gate |
| Model bazlı CRUD yetkilendirme | Policy |
| Genel admin kontrolü | Gate |
| "Bu kullanıcı bu kaydı düzenleyebilir mi?" | Policy |
| Karışık roller ve izinler | Spatie Permission |
Pratikte ikisi birlikte kullanılır. Gate genel erişim kontrolleri için, Policy model operasyonları için.
İleri Seviye: Spatie Permission
Daha karmaşık senaryolar için:
composer require spatie/laravel-permission
// Role ve permission tanımlama
$role = Role::create(['name' => 'editor']);
$permission = Permission::create(['name' => 'publish posts']);
$role->givePermissionTo($permission);
// Kullanıcıya atama
$user->assignRole('editor');
// Kontrol
if ($user->can('publish posts')) {
// ...
}
Sonuç
Laravel'in Gate ve Policy mekanizmaları yetkilendirme için güçlü bir temel sağlar. Gate basit kontroller için, Policy model bazlı işlemler için ideal. Daha karmaşık rol/izin sistemleri gerektiğinde Spatie Permission paketi harika bir eklenti. Önemli olan: yetkilendirmeyi baştan doğru planlamak — sonradan eklemek çok daha zor.