Latar Belakang
Sebagai lanjutan dari pembahasan mengenai Blade di Laravel, tahap berikutnya adalah mempelajari mekanisme otorisasi menggunakan Policy dan Gate. Dalam pengembangan aplikasi, tidak cukup hanya memastikan pengguna telah melakukan autentikasi, tetapi juga perlu menentukan apakah pengguna tersebut memiliki izin untuk melakukan tindakan tertentu. Oleh karena itu, diperlukan sistem otorisasi yang dapat mengatur hak akses pengguna secara lebih spesifik.
Artikel ini dibuat dengan tujuan untuk mendokumentasikan hasil pembelajaran saya mengenai penggunaan Policy dan Gate dalam Laravel. Dengan memahami konsep ini, saya dapat mengontrol akses pengguna terhadap fitur tertentu dalam aplikasi sehingga sistem menjadi lebih aman dan terorganisir.
Alat dan Bahan
A. Perangkat Lunak
- Web browser (Google Chrome)
- Code editor (Visual Studio Code)
- Terminal
- Web server
- Composer
- PHP
- Laravel
B. Perangkat Keras
- Laptop
Pendahuluan
Pernahkah Anda membayangkan jika semua pengguna di sebuah aplikasi toko online bisa mengedit harga barang, menghapus produk orang lain, atau bahkan mengakses data pengguna lain? Tentunya akan terjadi kekacauan, bukan? Di sinilah pentingnya sistem authorization dalam aplikasi web.
Sebelum melangkah lebih jauh, mari kita pahami dulu dua konsep yang sering membingungkan: Role dan Authorization.
Role adalah identitas atau peran yang melekat pada pengguna dalam sistem. Misalnya dalam aplikasi toko online, kita memiliki:
-
Admin → memiliki kendali penuh atas aplikasi
-
Seller → bisa mengelola produk miliknya sendiri
-
Customer → hanya bisa melihat dan membeli produk
Sementara itu, Authorization adalah proses yang menentukan tindakan apa yang boleh dilakukan oleh pengguna berdasarkan rolenya. Contoh sederhana:
-
Seorang seller hanya boleh mengedit produk miliknya sendiri
-
Admin boleh menghapus produk apapun, termasuk milik seller lain
-
Customer hanya boleh melihat produk, tidak bisa mengedit atau menghapus
Laravel, sebagai framework PHP yang elegan, menyediakan dua mekanisme authorization yang powerfull: Gate dan Policy. Keduanya membantu kita mengatur "siapa boleh melakukan apa" dalam aplikasi dengan cara yang terstruktur dan mudah dipahami.
Memahami Konsep Gate
Gate dalam Laravel bisa diibaratkan seperti "pintu masuk" yang menentukan apakah seseorang boleh melewatinya atau tidak. Gate adalah pendekatan sederhana untuk mengecek izin, biasanya berbasis closure atau callback function.
Kapan Menggunakan Gate?
Gate sangat cocok digunakan untuk aturan authorization yang sederhana dan tidak terlalu kompleks. Misalnya, mengecek apakah user adalah pemilik dari sebuah data.
Dimana Mendefinisikan Gate?
Kita mendefinisikan Gate di dalam file App\Providers\AuthServiceProvider.php, tepatnya di method boot().
Contoh Implementasi Gate
Mari kita lihat contoh dalam konteks toko online. Misalkan kita ingin memastikan bahwa hanya pemilik produk yang bisa mengupdate produknya:
// App\Providers\AuthServiceProvider.php
use Illuminate\Support\Facades\Gate;
use App\Models\Product;
public function boot()
{
Gate::define('update-product', function ($user, $product) {
return $user->id === $product->seller_id;
});
}
Mari kita bedah kode di atas:
-
Parameter pertama
'update-product'adalah nama gate yang akan kita panggil nantinya -
Parameter kedua adalah closure function yang menerima dua parameter:
$user(user yang sedang login) dan$product(produk yang akan diedit) -
Kondisi
$user->id === $product->seller_idmengecek apakah ID user yang login sama dengan ID seller pemilik produk -
Jika kondisi terpenuhi (bernilai true), maka user diizinkan mengupdate produk
Menggunakan Gate di Controller
Setelah mendefinisikan Gate, langkah selanjutnya adalah menggunakannya di controller. Laravel menyediakan method authorize() yang sangat mudah digunakan.
Contoh Controller untuk Update Produk
// App\Http\Controllers\ProductController.php
public function edit($id)
{
$product = Product::findOrFail($id);
// Cek apakah user berhak mengupdate produk ini
Gate::authorize('update-product', $product);
// Jika lolos pengecekan, tampilkan form edit
return view('products.edit', compact('product'));
}
public function update(Request $request, $id)
{
$product = Product::findOrFail($id);
// Cek authorization lagi sebelum menyimpan perubahan
Gate::authorize('update-product', $product);
// Validasi data
$validated = $request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0'
]);
// Update produk
$product->update($validated);
return redirect()->route('products.index')
->with('success', 'Produk berhasil diperbarui');
}
Cara kerja Gate::authorize():
-
Method ini akan secara otomatis mengecek user yang sedang login
-
Jika user tidak memiliki izin, Laravel akan melemparkan AuthorizationException dan menampilkan halaman error 403 Forbidden
-
Jika user memiliki izin, proses akan dilanjutkan ke baris kode berikutnya
Menggunakan Gate di Blade
Salah satu kelebihan Laravel adalah kemampuannya mengatur tampilan berdasarkan izin user. Kita bisa menyembunyikan tombol edit dari user yang tidak berhak mengedit produk.
{{-- resources/views/products/index.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Daftar Produk</h1>
@foreach($products as $product)
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">{{ $product->name }}</h5>
<p class="card-text">
Harga: Rp {{ number_format($product->price) }}<br>
Stok: {{ $product->stock }}
</p>
{{-- Tombol Edit hanya tampil jika user memiliki izin --}}
@can('update-product', $product)
<a href="{{ route('products.edit', $product->id) }}"
class="btn btn-warning">
Edit
</a>
@endcan
{{-- Tombol Hapus dengan directive @cannot --}}
@cannot('update-product', $product)
<button class="btn btn-secondary" disabled>
Tidak bisa edit
</button>
@endcannot
</div>
</div>
@endforeach
</div>
@endsection
Laravel juga menyediakan directive lain seperti @canany untuk mengecek beberapa izin sekaligus:
@canany(['update-product', 'delete-product'], $product)
<div class="alert alert-info">
Anda memiliki akses untuk mengelola produk ini
</div>
@endcanany
Membuat Policy untuk Authorization yang Lebih Terstruktur
Saat aplikasi semakin kompleks, aturan authorization pun akan semakin banyak. Misalnya untuk produk saja kita mungkin perlu aturan:
-
Siapa yang boleh melihat produk?
-
Siapa yang boleh membuat produk?
-
Siapa yang boleh mengupdate produk?
-
Siapa yang boleh menghapus produk?
-
Siapa yang boleh mengubah stok?
Jika semua aturan ini ditulis sebagai Gate, file AuthServiceProvider akan menjadi sangat panjang dan sulit dipelihara. Solusinya adalah menggunakan Policy.
Policy adalah kelas yang mengelompokkan aturan authorization berdasarkan model tertentu. Dengan Policy, kode menjadi lebih terstruktur dan mudah dikelola.
Membuat Policy
Gunakan Artisan command untuk membuat policy:
php artisan make:policy ProductPolicy --model=Product
Flag --model=Product akan secara otomatis membuat method-method standar yang biasa digunakan untuk model Product.
Struktur Policy
// App\Policies\ProductPolicy.php
namespace App\Policies;
use App\Models\Product;
use App\Models\User;
class ProductPolicy
{
/**
* Menentukan apakah user bisa melihat daftar produk
*/
public function viewAny(User $user): bool
{
return true; // Semua user bisa melihat daftar produk
}
/**
* Menentukan apakah user bisa melihat detail produk
*/
public function view(User $user, Product $product): bool
{
return true; // Semua user bisa melihat detail
}
/**
* Menentukan apakah user bisa membuat produk baru
*/
public function create(User $user): bool
{
// Hanya seller yang bisa membuat produk
return $user->role === 'seller' || $user->role === 'admin';
}
/**
* Menentukan apakah user bisa mengupdate produk
*/
public function update(User $user, Product $product): bool
{
// Pemilik produk atau admin boleh mengupdate
return $user->id === $product->seller_id || $user->role === 'admin';
}
/**
* Menentukan apakah user bisa menghapus produk
*/
public function delete(User $user, Product $product): bool
{
// Hanya admin yang boleh menghapus produk
return $user->role === 'admin';
}
/**
* Menentukan apakah user bisa mengembalikan produk yang dihapus
*/
public function restore(User $user, Product $product): bool
{
return $user->role === 'admin';
}
/**
* Menentukan apakah user bisa menghapus produk secara permanen
*/
public function forceDelete(User $user, Product $product): bool
{
return $user->role === 'admin';
}
}
Menggunakan Policy di Controller dan Blade
Mendaftarkan Policy
Langkah pertama adalah mendaftarkan Policy di AuthServiceProvider:
// App\Providers\AuthServiceProvider.php
use App\Models\Product;
use App\Policies\ProductPolicy;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Product::class => ProductPolicy::class,
];
public function boot()
{
$this->registerPolicies();
}
}
Dengan pendaftaran ini, Laravel akan otomatis menghubungkan model Product dengan ProductPolicy.
Menggunakan Policy di Controller
// App\Http\Controllers\ProductController.php
public function store(Request $request)
{
// Cek apakah user boleh membuat produk
$this->authorize('create', Product::class);
// Validasi dan simpan produk
$validated = $request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0'
]);
$product = Product::create([
'seller_id' => auth()->id(),
...$validated
]);
return redirect()->route('products.index')
->with('success', 'Produk berhasil ditambahkan');
}
public function destroy($id)
{
$product = Product::findOrFail($id);
// Cek apakah user boleh menghapus produk
$this->authorize('delete', $product);
$product->delete();
return redirect()->route('products.index')
->with('success', 'Produk berhasil dihapus');
}
Cara Kerja $this->authorize():
-
Untuk method create, kita menggunakan
Product::classkarena tidak ada instance produk spesifik -
Untuk method delete, kita menggunakan
$productkarena perlu mengecek kepemilikan produk -
Laravel akan secara otomatis memanggil method yang sesuai di ProductPolicy
Menggunakan Policy di Blade
{{-- resources/views/products/show.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
<h1>{{ $product->name }}</h1>
<div class="card">
<div class="card-body">
<p>Harga: Rp {{ number_format($product->price) }}</p>
<p>Stok: {{ $product->stock }}</p>
<p>Seller: {{ $product->seller->name }}</p>
</div>
</div>
<div class="mt-3">
{{-- Tombol Edit --}}
@can('update', $product)
<a href="{{ route('products.edit', $product->id) }}"
class="btn btn-warning">
Edit Produk
</a>
@endcan
{{-- Tombol Hapus --}}
@can('delete', $product)
<form action="{{ route('products.destroy', $product->id) }}"
method="POST"
class="d-inline">
@csrf
@method('DELETE')
<button type="submit"
class="btn btn-danger"
onclick="return confirm('Yakin ingin menghapus?')">
Hapus Produk
</button>
</form>
@endcan
{{-- Informasi khusus --}}
@cannot('update', $product)
<div class="alert alert-info">
Anda tidak memiliki akses untuk mengedit produk ini
</div>
@endcannot
</div>
</div>
@endsectionHasil Pembelajaran
Melalui pembelajaran ini, saya memahami bahwa Gate digunakan untuk mendefinisikan aturan otorisasi secara sederhana, biasanya untuk memeriksa apakah pengguna memiliki izin untuk melakukan suatu tindakan tertentu. Gate dapat didefinisikan dalam aplikasi dan digunakan untuk membatasi akses terhadap fitur atau proses tertentu.
Selain itu, saya juga mempelajari bahwa Policy digunakan untuk mengelola aturan otorisasi yang lebih terstruktur dan biasanya berkaitan langsung dengan model tertentu. Dengan menggunakan Policy, aturan akses dapat dikelompokkan berdasarkan model sehingga lebih mudah dikelola ketika aplikasi memiliki banyak fitur yang memerlukan pengaturan hak akses.
Kesimpulan
Policy dan Gate merupakan bagian penting dalam sistem otorisasi di Laravel. Kedua mekanisme ini membantu dalam mengatur hak akses pengguna terhadap fitur tertentu dalam aplikasi secara lebih terstruktur dan aman.
Dengan memahami penggunaan Policy dan Gate, saya dapat membangun sistem yang tidak hanya memastikan pengguna telah terautentikasi, tetapi juga memastikan bahwa setiap tindakan yang dilakukan sesuai dengan hak akses yang dimiliki pengguna.