Skip to main content

Spatie/laravel-permission

Daftar istilah:

  • roles = peranan
  • permission = perizinan
  • user = pengguna
  • policies/policy = kebijakan

Introduction (Pendahuluan)​

Package ini mengizinkan Anda untuk memanajemen user permissions dan roles di database.

Setelah terinstal, Anda dapat melakukan hal-hal seperti ini:

// Menambahkan permissions ke user
$user->givePermissionTo('edit articles');

// Menambahkan permissions menggunakan roles
$user->assignRole('writer');

$roleWriter->givePermissionTo('edit articles');

Jika Anda menggunakan multiple guards dalam Laravel, Spatie Permission dapat menangani kasus tersebut dengan baik. Setiap guard akan memiliki seperangkat permissions dan roles sendiri. Baca lebih lanjut tentang ini pada section [using multiple guards].

Karena semua permissions akan terdaftar pada gate (pintu gerbang) Laravel, Anda dapat memeriksa apakah seseorang user memiliki permissions dengan menggunakan default function can pada Laravel:

$user->can('edit articles');

dan menggunakan directive Blade:

@can('edit articles')
// Konten yang hanya ditampilkan jika _user_ memiliki `permissions` untuk mengedit artikel
// ...
@endcan

Prerequisites (Persyaratan)​

Laravel Version​

Package ini dapat digunakan dengan Laravel versi 6 atau yang lebih tinggi. Anda dapat memeriksa halaman "[Installing on Laravel]" untuk mengetahui versi Package yang kompatibel dengan berbagai versi Laravel. Dengan demikian, Anda dapat memastikan bahwa Anda menggunakan versi Package yang sesuai dengan versi Laravel yang Anda gunakan.

User Model / Contract / Interface​

Package ini menggunakan lapisan Gate Laravel untuk menyediakan kemampuan Authorization (otorisasi). Lapisan Gate/authorization memerlukan model User Anda untuk implement contract Illuminate\Contracts\Auth\Access\Authorizable. Jika tidak, method can() dan authorize() tidak akan berfungsi dalam controllers, policies, templates, dll.

Dalam instruksi [Instalasi], Anda akan melihat bahwa trait HasRoles harus ditambahkan ke model User untuk enable (mengaktifkan) fitur-fitur Package ini.

Dengan demikian, model User dasar biasanya akan memiliki persyaratan minimum berikut:

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
use HasRoles;
// ...
}

TIDAK BOLEH memiliki property role atau roles, maupun method roles()​

Model User Anda TIDAK BOLEH memiliki property role atau roles (atau field dalam database dengan nama tersebut), atau method roles(). Hal ini akan mengganggu property dan method yang ditambahkan oleh trait HasRoles yang disediakan oleh package ini, sehingga menyebabkan hasil yang tidak diharapkan saat method package ini digunakan untuk memeriksa roles dan permissions.

TIDAK BOLEH memiliki property permission atau permissions, maupun method permission()​

Model User Anda tidak boleh memiliki property permission atau permissions (atau field dalam database dengan nama tersebut), atau method permissions(). Hal ini akan mengganggu property dan method yang ditambahkan oleh trait HasPermissions yang disediakan oleh package ini (yang invoked (dipanggil) melalui trait HasRoles).

// vendor\spatie\laravel-permission\src\Traits\HasRoles.php
namespace Spatie\Permission\Traits;

// code lain disembunyikan

trait HasRoles
{
use HasPermissions;
// code lain disembunyikan
}

Config file​

Package ini akan publishes file config/permission.php. Jika Anda sudah memiliki file dengan nama tersebut, Anda harus mengganti nama atau menghapusnya, karena akan conflict (bentrok) dengan package ini. Anda dapat secara opsional menggabungkan nilai-nilai Anda sendiri dengan yang diperlukan oleh package ini, selama kunci-kunci yang diharapkan oleh package ini ada. Lihat file sumber untuk lebih detail.

Schema Limitation in MySQL​

Pada MySQL 8.0 membatasi index keys menjadi 1000 characters. package ini publishes (menerbitkan) migration yang menggabungkan beberapa columns dalam single index (satu index). Dengan utf8mb4, persyaratan 4-bytes-per-character dari mb4 berarti max length (panjang maksimum) columns dalam hybrid index hanya dapat menjadi 125 characters.

Oleh karena itu, dalam AppServiceProvider Anda perlu mengatur Schema::defaultStringLength(125). Lihat petunjuk pada Dokumentasi Laravel.

Anda mungkin dapat mengabaikan pengaturan defaultStringLength(125) dengan mengedit migration dan menentukan 125 char di 4 field. Ada 2 contoh potongan kode di mana Anda dapat secara eksplisit mengatur 125 char:

$table->string('name');       // For MySQL 8.0 use string('name', 125);
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);

Catatan untuk aplikasi yang menggunakan UUID/ULID/GUID​

Package ini mengharapkan primary key dari model User Anda untuk menjadi auto-incrementing int (yang bertambah secara otomatis). Jika tidak, Anda mungkin perlu memodifikasi migration create_permission_tables dan/atau mengubah konfigurasi default. Lihat https://spatie.be/docs/laravel-permission/advanced-usage/uuid untuk informasi lebih lanjut.

Database foreign-key relationship support​

Package ini menggunakan relationship foreign-key pada database dengan cascading deletes untuk menerapkan integritas database. Hal ini mencegah situasi ketidaksesuaian data jika records database dimanipulasi di luar package ini. Jika database engine Anda tidak mendukung relationship foreign-key, maka Anda harus mengubah file migration sesuai dengan kebutuhan.

Package ini melakukan detaching terpisah dari pivot records saat penghapusan dilakukan menggunakan method yang disediakan oleh package ini. Jadi, jika database Anda tidak mendukung foreign key, selama Anda hanya menggunakan panggilan method yang disediakan oleh package ini untuk mengelola records terkait, seharusnya tidak ada masalah integritas data.

Installation in Laravel​

Laravel Version Compatibility​

Lihat pada Laravel Version Compatibility

Installing​

Ini adalah instruksi untuk install package Spatie Laravel Permission. Beberapa hal yang perlu diperhatikan sebelum instalasi adalah:

  • Pastikan untuk memeriksa [Prerequisites] page untuk pertimbangan penting mengenai model User Anda!
  • Package ini akan publishes file config/permission.php. Jika Anda sudah memiliki file dengan nama tersebut, Anda harus mengubah nama atau menghapusnya.

Langkah-langkah untuk install package ini adalah sebagai berikut:

  1. Install package melalui Composer dengan perintah:
composer require spatie/laravel-permission
  1. Optional: package ini akan mendaftarkan service provider secara otomatis. Atau Anda dapat menambahkan service provider secara manual di file config/app.php:
'providers' => [
// ...
Spatie\Permission\PermissionServiceProvider::class,
];
  1. Publish migration dan config file config/permission.php dengan perintah:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

SEBELUM MENJALANKAN migration

  • Jika Anda menggunakan UUID, lihat bagian Advanced pada dokumen tentang langkah-langkah UUID sebelum melanjutkan. Hal ini menjelaskan beberapa perubahan yang mungkin ingin Anda buat pada migration dan config file sebelum melanjutkan.
  • Jika Anda akan menggunakan fitur TEAMS, Anda harus memperbarui config file config/permission.php:
    • Anda harus mengatur 'teams' => true,
    • dan (opsional) Anda dapat mengatur nama team_foreign_key di config file jika Anda ingin menggunakan foreign key kustom di database Anda untuk tim.
  • Jika Anda menggunakan MySQL 8, lihat file migration untuk catatan tentang MySQL 8 untuk mengatur/membatasi panjang index key, dan edit sesuai kebutuhan. Jika Anda mendapatkan ERROR: 1071 Specified key was too long maka Anda perlu melakukan ini.
  1. Bersihkan cache konfigurasi Anda. Package ini memerlukan akses ke pengaturan konfigurasi permission agar dapat menjalankan migration. Jika Anda telah mem-cache konfigurasi secara lokal, bersihkan cache konfigurasi Anda dengan salah satu dari perintah berikut:
php artisan optimize:clear

atau

php artisan config:clear
  1. Jalankan migration: Setelah konfigurasi telah dipublikasikan dan dikonfigurasi, Anda dapat membuat tabel untuk package ini dengan menjalankan migration, dengan perintah:
php artisan migrate
  1. Tambahkan trait yang diperlukan ke model User Anda:
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
use HasRoles;
// ...
}
  1. Anda dapat mulai menggunakan fitur-fitur package ini dengan membaca bagian Basic Usage pada dokumentasinya.

Default config file contents​

Anda dapat melihat isi config file default di: https://github.com/spatie/laravel-permission/blob/main/config/permission.php

Membuat Seeder​

php artisan make:seeder RoleSeeder
php artisan make:seeder PermissionSeeder

Basic Usage (Penggunaan Dasar)​

Ini adalah petunjuk dasar penggunaan Spatie Laravel Permission. Berikut adalah penjelasan dari setiap langkah:

Add The Trait​

Menambahkan Trait: Pertama, Anda perlu menambahkan trait Spatie\Permission\Traits\HasRoles ke model User Anda. Dengan menambahkan trait ini, model User akan memiliki kemampuan untuk memiliki roles dan permissions.

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
use HasRoles;
// ...
}

Create A Permission​

Membuat permissions: Package ini memungkinkan user untuk berelasi dengan permissions dan roles. Setiap role berelasi dengan beberapa permissions. Role dan Permission adalah model Eloquent biasa. Mereka require name dan dapat dibuat seperti ini:

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);

Assign A Permission To A Role​

Menetapkan permission ke role: permission dapat ditetapkan (assign) ke role menggunakan salah satu dari method berikut:

$role->givePermissionTo($permission); // peran diberi izin untuk ...
$permission->assignRole($role); // ijin ini ditetapkan ke peran ...

Sync Permissions To A Role​

Menyinkronkan permission ke role: Beberapa permissions dapat disinkronkan ke role menggunakan salah satu dari method berikut:

$role->syncPermissions($permissions);
$permission->syncRoles($roles);

Remove Permission From A Role​

Menghapus permission dari role: permission dapat dihapus dari role menggunakan salah satu dari method berikut:

$role->revokePermissionTo($permission);
$permission->removeRole($role);

Guard Name​

Nama Penjaga: Jika Anda menggunakan beberapa penjaga (guards), maka atribut guard_name juga harus diatur. Anda dapat membaca tentang ini di bagian using multiple guards dari readme.

Get Permissions For A User​

Mendapatkan permissions untuk User: Trait HasRoles menambahkan relasi Eloquent ke model Anda, yang dapat diakses secara langsung atau digunakan sebagai query dasar.

// get a list of all permissions directly assigned to the user
$permissionNames = $user->getPermissionNames(); // collection of name strings
$permissions = $user->permissions; // collection of permission objects

// get all permissions for the user, either directly, or from roles, or from both
$permissions = $user->getDirectPermissions();
$permissions = $user->getPermissionsViaRoles();
$permissions = $user->getAllPermissions();

// get the names of the user's roles
$roles = $user->getRoleNames(); // Returns a collection

Scopes​

Cakupan: Trait HasRoles juga menambahkan cakupan role dan withoutRole ke model Anda untuk membatasi query ke roles atau permissions tertentu.

$writerUsers = User::role('writer')->get(); // Returns only users with the role 'writer'
$nonEditorUsers = User::withoutRole('editor')->get(); // Returns only users without the role 'editor'

Cakupan role dan withoutRole dapat menerima string, object \Spatie\Permission\Models\Role, atau object \Illuminate\Support\Collection.

Trait yang sama juga menambahkan cakupan hanya untuk get users yang memiliki atau tidak memiliki permissions tertentu.

$users = User::permission('edit articles')->get(); // Returns only users with the permission 'edit articles' (inherited or directly)
$usersWhoCannotEditArticles = User::withoutPermission('edit articles')->get(); // Returns all users without the permission 'edit articles' (inherited or directly)

The scope can accept a string, a \Spatie\Permission\Models\Permission object or an \Illuminate\Support\Collection object.

Eloquent Calls​

Panggilan Eloquent: Karena model Role dan Permission extended dari model Eloquent, Eloquent Calls dasar juga dapat digunakan.

$all_users_with_all_their_roles = User::with('roles')->get();
$all_users_with_all_their_direct_permissions = User::with('permissions')->get();
$all_roles_in_database = Role::all()->pluck('name');
$users_without_any_roles = User::doesntHave('roles')->get();
$all_roles_except_a_and_b = Role::whereNotIn('name', ['role A', 'role B'])->get();

Counting Users Having A Role​

Menghitung User yang Memiliki roles: Salah satu cara untuk menghitung semua user yang memiliki suatu roles adalah dengan menyaring collection semua user dengan roles mereka:

$superAdminCount = User::with('roles')->get()->filter(
fn ($user) => $user->roles->where('name', 'Super Admin')->toArray()
)->count();

Best-Practice​

Roles vs Permissions​

Ini adalah panduan praktik terbaik untuk memahami perbedaan antara Peran (Roles) dan Izin (Permissions):

  • Peran (Roles):
    • Role adalah sekelompok Permission yang diberikan kepada User.
    • Mereka digunakan untuk "mengelompokkan" User berdasarkan "set Permission" tertentu.
    • Ini memberikan gambaran umum tentang apa yang dapat dilakukan oleh sekelompok User tertentu.
  • Izin (Permissions):
    • Permission adalah hak akses yang spesifik untuk fitur atau tindakan (action) tertentu.
    • Permission sebaiknya ditetapkan ke Role, "bukan langsung" ke User.
    • Semakin terperinci dan deskriptif name Permission (izin seperti view document dan edit document ), semakin mudah mengontrol akses dalam aplikasi.
  • Pengguna (Users):
    • User sebaiknya jangan diberikan Permission secara langsung.
    • Lebih baik jika User mewarisi Permission melalui Role yang ditetapkan kepada mereka.
  • Penggunaan @can atau can() Directive:
    • Selalu gunakan directive blade @can dan can() bawaan Laravel, dengan begitu Anda dapat memeriksa User Permission di seluruh aplikasi.
    • Ini memungkinkan layer Gate Laravel untuk menangani sebagian besar pekerjaan beratnya.
    • Menguji Permission secara langsung dengan @can dan can() lebih aman daripada menguji Role langsung dengan $user->hasRole('Role').
    • Lebih Aman untuk Menggunakan Permission Daripada Role:
      • Lebih aman jika tampilan (Views) Anda memeriksa permission khusus seperti @can('view member addresses') atau @can('edit document'), bukan menguji langsung role user dengan $user->hasRole('Editor').
      • Ini karena memeriksa permission memberi tingkat kontrol yang lebih spesifik.
    • Kontrol Tampilan Konten vs Tombol Edit/Hapus:
      • Dengan menggunakan permission terpisah seperti "view document" dan "edit document", Anda dapat lebih mudah mengontrol bagaimana konten ditampilkan dan tombol edit/hapus diperlihatkan.
      • Misalnya, jika sebuah user memiliki permission "view document" tetapi tidak "edit document", Anda dapat menampilkan konten dokumen tersebut tetapi tidak menampilkan tombol untuk mengedit atau menghapus dokumen tersebut.
    • Role Penulis:
      • Dalam contoh tersebut, role "Penulis" (Writer) akan diberikan kedua permission "view" dan "edit".
      • Ini berarti user yang memiliki role "Penulis" akan memiliki kemampuan untuk melihat dan mengedit dokumen.
    • User Mendapatkan role Penulis:
      • Kemudian, user akan diberikan role "Penulis" (Writer), yang berarti mereka akan mewarisi permission "view" dan "edit" yang terkait dengan role tersebut.
      • Dengan cara ini, Anda dapat mengatur permission dengan lebih fleksibel, di mana user dapat diberikan role yang sesuai dengan tugas atau tanggung jawab mereka dalam aplikasi.
  • Ringkasan:
    • users memiliki Roles.
    • roles memiliki Permissions.
    • Aplikasi selalu memeriksa izin (sebanyak mungkin), bukan roles.
    • views check permission-names
    • policies (kebijakan) check permission-names
    • model policies check permission-names
    • controller methods check permission-names
    • middleware check permission-names, atau kadang-kadang role-names
    • routes check permission-names, atau mungkin role-names jika Anda perlu membuat kode seperti itu.

Terkadang kelompok aturan route tertentu mungkin lebih masuk akal untuk mengelompokkannya berdasarkan role, namun tetap saja, jika memungkinkan, biaya overhead yang digunakan akan lebih sedikit jika Anda dapat memeriksa permission tertentu.

Membuat Policy Role dan Permission​

Role​

php artisan make:policy RolePolicy --model=Role
app\Policies\RolePolicy.php
<?php

namespace App\Policies;

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Spatie\Permission\Models\Role;

class RolePolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can view the model.
*/
public function view(User $user, Role $role): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can update the model.
*/
public function update(User $user, Role $role): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Role $role): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Role $role): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Role $role): bool
{
return $user->isSuperAdmin();
}
}


Permission​

php artisan make:policy PermissionPolicy --model=Permission
app\Policies\PermissionPolicy.php
<?php

namespace App\Policies;

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Spatie\Permission\Models\Permission;

class PermissionPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can view the model.
*/
public function view(User $user, Permission $permission): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can update the model.
*/
public function update(User $user, Permission $permission): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Permission $permission): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Permission $permission): bool
{
return $user->isSuperAdmin();
}

/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Permission $permission): bool
{
return $user->isSuperAdmin();
}
}

AuthServiceProvider​

Tambahkan pengaturan $policies pada AuthServiceProvider.php supaya terhubung antara RolePolicy.php dengan model yang ada pada spatie Role.php.

app\Providers\AuthServiceProvider.php
<?php

namespace App\Providers;

use App\Models\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
\Spatie\Permission\Models\Role::class => \App\Policies\RolePolicy::class,
\Spatie\Permission\Models\Permission::class => \App\Policies\PermissionPolicy::class,
];

/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
// Harus ada trait HasSuperAdmin pada model User.php (package terpisah)
Gate::before(function (User $user, string $ability) {
return $user->isSuperAdmin() ? true : null;
});

// Melakukan logging perintah query ke database
// storage\logs\laravel.log
DB::listen(function ($query) {
Log::info("Query : {$query->sql}");
});
}
}