Gate dan Policy: Otorisasi
Atur siapa boleh apa dengan Gate untuk aksi sederhana dan Policy untuk otorisasi per model.
Authentication vs authorization
Authentication menjawab "siapa kamu?" (login). Authorization menjawab "bolehkah kamu melakukan ini?". Middleware auth menangani yang pertama, Gate dan Policy menangani yang kedua.
Gate: untuk aksi sederhana
Gate cocok untuk izin yang tidak terikat model tertentu, misalnya akses halaman admin:
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::define('akses-laporan', function (User $user) {
return $user->is_admin || $user->jabatan === 'keuangan';
});
}Pakai di controller, route, atau Blade:
// Controller
if (Gate::denies('akses-laporan')) {
abort(403);
}
// Atau helper yang otomatis 403
Gate::authorize('akses-laporan');
// Blade
@can('akses-laporan')
<a href="/laporan">Lihat Laporan</a>
@endcanPolicy: otorisasi per model
Policy adalah class yang mengelompokkan semua aturan untuk satu model. Cocok untuk pertanyaan seperti "bolehkah user ini mengedit post ini?":
php artisan make:policy PostPolicy --model=Post// app/Policies/PostPolicy.php
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 || $user->is_admin;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}Laravel otomatis menemukan PostPolicy untuk model Post kalau mengikuti konvensi nama. Pakainya:
// Di controller: otomatis 403 kalau tidak boleh
$this->authorize('update', $post);
// Di Form Request
public function authorize(): bool
{
return $this->user()->can('update', $this->post);
}
// Di Blade
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcanCatatan teknis: Jangan campur logika otorisasi di Blade atau controller secara acak. Pusatkan di Policy supaya aturannya konsisten: tombol edit disembunyikan di Blade DAN request edit ditolak di controller. Menyembunyikan tombol saja tanpa cek di backend sama dengan tidak ada proteksi, karena user bisa menembak URL langsung.