Artikel ini melanjutkan penjelasan konsep Policy dan Gate di Laravel 12 dengan studi kasus implementasi lengkap: sistem manajemen konten dengan beberapa level akses.
Studi Kasus: Sistem CMS dengan Multi-Role
Skenario: aplikasi CMS dengan role admin, editor, dan author. Aturannya:
- Admin bisa lakukan semua aksi di artikel mana saja
- Editor bisa buat, edit, dan publish artikel mana saja
- Author hanya bisa buat dan edit artikel miliknya sendiri
Setup Model User dengan Role
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $fillable = ['name', 'email', 'password', 'role'];
public function isAdmin(): bool
{
return $this->role === 'admin';
}
public function isEditor(): bool
{
return in_array($this->role, ['admin', 'editor']);
}
}
ArticlePolicy Lengkap
<?php
namespace App\Policies;
use App\Models\Article;
use App\Models\User;
class ArticlePolicy
{
// Ini dijalankan sebelum semua method lain
// Return true = admin bypass semua check
public function before(User $user, string $ability): ?bool
{
if ($user->isAdmin()) {
return true;
}
return null; // null = lanjut ke check berikutnya
}
public function viewAny(?User $user): bool
{
// Semua orang bisa lihat daftar artikel yang published
return true;
}
public function view(?User $user, Article $article): bool
{
if ($article->status === 'published') {
return true;
}
// Draft hanya bisa dilihat pemilik atau editor
return $user && ($article->user_id === $user->id || $user->isEditor());
}
public function create(User $user): bool
{
return $user->hasVerifiedEmail();
}
public function update(User $user, Article $article): bool
{
// Editor bisa edit semua, author hanya punya sendiri
return $user->isEditor() || $article->user_id === $user->id;
}
public function delete(User $user, Article $article): bool
{
// Hanya admin (via before()) atau pemilik artikel
return $article->user_id === $user->id;
}
public function publish(User $user, Article $article): bool
{
// Hanya editor ke atas yang bisa publish
return $user->isEditor();
}
public function restore(User $user, Article $article): bool
{
return $user->isEditor() || $article->user_id === $user->id;
}
}
Menggunakan Policy di Controller
<?php
namespace App\Http\Controllers;
use App\Models\Article;
use App\Http\Requests\StoreArticleRequest;
class ArticleController extends Controller
{
public function index()
{
$this->authorize('viewAny', Article::class);
$articles = Article::with('author')
->when(!auth()->user()?->isEditor(), fn ($q) =>
$q->where('status', 'published')
->orWhere('user_id', auth()->id())
)
->paginate(15);
return view('articles.index', compact('articles'));
}
public function edit(Article $article)
{
$this->authorize('update', $article);
return view('articles.edit', compact('article'));
}
public function destroy(Article $article)
{
$this->authorize('delete', $article);
$article->delete();
return redirect()->route('articles.index')
->with('success', 'Artikel dihapus.');
}
public function publish(Article $article)
{
$this->authorize('publish', $article);
$article->update(['status' => 'published', 'published_at' => now()]);
return back()->with('success', 'Artikel dipublish.');
}
}
Policy di Blade Template
@foreach ($articles as $article)
<div>
<h2>{{ $article->title }}</h2>
@can('update', $article)
<a href="{{ route('articles.edit', $article) }}">Edit</a>
@endcan
@can('publish', $article)
@if($article->status === 'draft')
<form action="{{ route('articles.publish', $article) }}" method="POST">
@csrf @method('PATCH')
<button>Publish</button>
</form>
@endif
@endcan
@can('delete', $article)
<form action="{{ route('articles.destroy', $article) }}" method="POST">
@csrf @method('DELETE')
<button>Hapus</button>
</form>
@endcan
</div>
@endforeach
Gate untuk Aksi Global
Untuk akses fitur yang tidak terkait model tertentu, pakai Gate:
// Di AppServiceProvider
Gate::define('access-analytics', fn (User $user) => $user->isEditor());
Gate::define('export-all-data', fn (User $user) => $user->isAdmin());
// Di controller
Gate::authorize('access-analytics');
return view('analytics.dashboard');
// Di Blade
@can('access-analytics')
<a href="/analytics">Analytics</a>
@endcan
Baca Juga
Butuh tim yang bantu implementasi sistem otorisasi yang tepat untuk aplikasi Laravel Anda? Lihat layanan pengembangan aplikasi kami.
Leave a Reply