Belajar Laravel - Authorization (Gates & Policies)
Episode 11 of 24

Belajar Laravel - Authorization (Gates & Policies)

Memisahkan authentication dari authorization: menerapkan Gates berbasis closure dan Policies per-model, $this->authorize() di controller, direktif @can di Blade, serta dasar RBAC/roles di Laravel 13.

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Di episode 10 kalian belajar "siapa yang boleh masuk" — itu authentication. Episode ini menjawab pertanyaan berikutnya yang jauh lebih bernuansa: "siapa yang boleh melakukan apa?" — itulah authorization. Sebuah user yang sudah login belum tentu boleh mengedit post orang lain, menghapus data, atau melihat halaman admin.

Menaruh logika izin di dalam controller dengan if berantakan adalah resep bug keamanan. Laravel menyediakan Gates dan Policies sebagai dua pendekatan yang rapi, terpusat, dan mudah diuji.

Authorization vs Authentication

AuthenticationAuthorization
Siapa kalian?Apa yang boleh kalian lakukan?
Login, session, kredensialIzin, role, kepemilikan data
Jawaban: identitasJawaban: ya/tidak
Di episode 10Di episode ini

Mereka berpasangan: authorization selalu berjalan setelah authentication. Tanpa auth, kita tidak punya user untuk diperiksa izinnya.

Gates: Authorization Berbasis Closure

Gates cocok untuk izin yang tidak terikat pada model tertentu — misalnya akses admin atau fitur global. Definisikan di AppServiceProvider::boot():

app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
 
Gate::define('manage-users', function (User $user) {
    return $user->is_admin;
});

Penggunaan di kode:

Memeriksa gate
if (Gate::allows('manage-users')) {
    // tampilkan panel admin
}
 
if (Gate::denies('manage-users')) {
    abort(403);
}

Gate menerima user otomatis sebagai argumen pertama, dan bisa menerima data tambahan — misalnya post yang sedang dicek:

Gate dengan parameter
Gate::define('update-post', function (User $user, Post $post) {
    return $user->id === $post->user_id;
});

Policies: Authorization Per-Model

Policies adalah cara yang lebih terorganisir untuk izin yang terkait erat dengan model. Generate dengan artisan:

Buat policy
php artisan make:policy PostPolicy --model=Post

File yang dihasilkan berisi method siap isi:

app/Policies/PostPolicy.php
<?php
 
namespace App\Policies;
 
use App\Models\Post;
use App\Models\User;
 
class PostPolicy
{
    public function view(User $user, Post $post): bool
    {
        return $user->id === $post->user_id || $user->is_admin;
    }
 
    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 13 memakai auto-discovery: policy dengan nama PostPolicy untuk model Post ditemukan otomatis tanpa registrasi manual.

authorize() di Controller

Di dalam controller, authorize() menyingkat seluruh logika izin menjadi satu baris:

Authorize di controller
public function update(UpdatePostRequest $request, Post $post)
{
    $this->authorize('update', $post);
 
    $post->update($request->validated());
 
    return redirect()->route('posts.index');
}

Jika user tidak berhak, Laravel otomatis melempar 403. Dengan Form Request + authorize(), controller jadi sangat bersih dan seluruh kebijakan tersentralisasi di satu file PostPolicy.

Direktif @can di Blade

Di tampilan, gunakan @can untuk menampilkan/menyembunyikan aksi sesuai izin:

Menampilkan tombol sesuai izin
@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan
 
@can('delete', $post)
    <form method="POST" action="{{ route('posts.destroy', $post) }}">
        @csrf
        @method('DELETE')
        <button>Hapus</button>
    </form>
@endcan

Tip

Aturan praktis pemisahan: Gates untuk izin global (misalnya manage-users, export-data), Policies untuk izin per model (update Post, delete Comment). Jangan memakai keduanya untuk tujuan yang sama secara tumpang tindih — konsistensi lebih penting daripada kelengkapan.

Dasar RBAC / Roles

Laravel tidak punya sistem role bawaan, tapi mudah dibangun dengan relasi:

Relasi role di model User
public function roles()
{
    return $this->belongsToMany(Role::class);
}
 
public function hasRole(string $role): bool
{
    return $this->roles()->where('name', $role)->exists();
}
Gate yang memakai role
Gate::define('edit-settings', function (User $user) {
    return $user->hasRole('admin');
});

Untuk sistem RBAC yang lebih lengkap (permission, super-admin, cache), package populer seperti Spatie Laravel-Permission menawarkan solusi siap pakai — tapi memahami pola di atas terlebih dahulu sangat disarankan sebelum memakai package.

Menguji Authorization

Authorization mudah diuji karena berbasis pure logic — tidak ada session:

Unit test policy
use App\Models\Post;
use App\Models\User;
 
test('only owner can update post', function () {
    $owner = User::factory()->create();
    $post = Post::factory()->for($owner)->create();
 
    $this->actingAs($owner)->put("/posts/{$post->id}", [...])->assertOk();
 
    $other = User::factory()->create();
    $this->actingAs($other)->put("/posts/{$post->id}", [...])->assertForbidden();
});

Penutup

Inti yang harus dibawa pulang:

  • Authentication menjawab "siapa", authorization menjawab "boleh apa".
  • Gates (closure) untuk izin global; Policies untuk izin per model.
  • $this->authorize('update', $post) di controller, @can di Blade.
  • Bangun role sederhana dengan belongsToMany sebelum naik ke package RBAC.

Di episode 12 selanjutnya kita akan membahas validation & error handling — aturan validasi lengkap, custom rules, Validator manual, Exception handler, custom exceptions, dan halaman error HTTP yang ramah pengguna. Sampai jumpa di episode 12!

Belajar Laravel - Authorization (Gates & Policies) | Belajar Laravel