· Admin

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 (PostPolicyPost 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.