Lompat ke konten
dokumentasi.id
Commit b472665
v1
Star1,3 rb

5

Manajemen User, Role, dan Permission

Badaso menyimpan model aksesnya di tiga tabel utama, users, roles, dan permissions, lalu menghubungkannya lewat dua tabel pivot: user_roles dan role_permissions. Kelima tabel itu ditangani oleh lima controller terpisah yang masing-masing mengekspos pola browse, read, add, edit, delete, dan deleteMultiple. Middleware config('badaso.middleware.check_permission') menjaga setiap route dengan sebuah permission key, misalnya browse_users untuk BadasoUserController@browse src/Routes/api.php:95-134. Mekanisme middleware itu sendiri dibahas di Autentikasi dan Otorisasi, sedangkan jejak perubahan tiap aksi dibahas di Media, Notifikasi, dan Activity Log.

Bentuk relasi antar tabel

Relasi Eloquent sejalan dengan skema migrasi. User::roles adalah belongsToMany ke Role melalui tabel user_roles src/Models/User.php:88-91, dan Role::permissions adalah belongsToMany ke Permission melalui role_permissions src/Models/Role.php:41-44. Kedua tabel pivot menyimpan foreign key user_id, role_id, permission_id beserta timestamps, dan keduanya memakai onDelete('cascade') sehingga menghapus user atau role ikut membersihkan baris pivotnya src/Migrations/2020_11_18_015852_create_user_roles.php:17-24 src/Migrations/2020_11_18_020028_create_role_permissions.php:17-24.

erDiagram
    users ||--o{ user_roles : "pivot"
    roles ||--o{ user_roles : "pivot"
    roles ||--o{ role_permissions : "pivot"
    permissions ||--o{ role_permissions : "pivot"
    users ||--o{ user_verifications : "token"

    users {
        bigint id PK
        string name
        string username
        string email
        string password
        string avatar
        datetime email_verified_at
    }

    roles {
        bigint id PK
        string name
        string display_name
        string description
    }

    permissions {
        bigint id PK
        string key
        string table_name
        string description
        string always_allow
        string is_public
        string roles_can_see_all_data
        string field_identify_related_user
    }

    user_roles {
        bigint id PK
        bigint user_id FK
        bigint role_id FK
    }

    role_permissions {
        bigint id PK
        bigint role_id FK
        bigint permission_id FK
    }

    user_verifications {
        bigint id PK
        bigint user_id FK
        string verification_token
        datetime expired_at
        integer count_incorrect
    }
%% fig: Relasi tabel user, role, dan permission
%% desc: Dua tabel pivot menghubungkan users ke roles dan roles ke permissions; user_verifications menyimpan token verifikasi per user.
Fig. 1: Relasi tabel user, role, dan permissionDua tabel pivot menghubungkan users ke roles dan roles ke permissions; user_verifications menyimpan token verifikasi per user.

Tabel user_verifications melengkapi skema ini dengan kolom verification_token yang unique, expired_at, dan count_incorrect src/Migrations/2021_03_09_064445_create_user_verifications.php:16-23. Model UserVerification memetakan kolom itu sebagai fillable dan menyediakan relasi belongsTo(User::class) src/Models/UserVerification.php:25-35.

Endpoint per resource

Kelima grup route memakai awalan yang sama dengan nama tabelnya, dan hampir semua handler memiliki permission key sendiri. Perhatikan bahwa grup user-roles dan role-permissions memakai key gabungan, bukan key per method src/Routes/api.php:95-134.

MethodPathHandlerpermission key
GET/users/BadasoUserController@browsebrowse_users
GET/users/readBadasoUserController@readread_users
PUT/users/editBadasoUserController@editedit_users
POST/users/addBadasoUserController@addadd_users
DELETE/users/deleteBadasoUserController@deletedelete_users
DELETE/users/delete-multipleBadasoUserController@deleteMultipledelete_users
GET/roles/BadasoRoleController@browsebrowse_roles
PUT/roles/editBadasoRoleController@editedit_roles
DELETE/roles/delete-multipleBadasoRoleController@deleteMultipledelete_roles
GET/permissions/BadasoPermissionController@browsebrowse_permissions
PUT/permissions/editBadasoPermissionController@editedit_permissions
DELETE/permissions/delete-multipleBadasoPermissionController@deleteMultipledelete_permissions
GET/user-roles/BadasoUserRoleController@browseByUserbrowse_user_role
GET/user-roles/allBadasoUserRoleController@browsebrowse_user_role
GET/user-roles/all-roleBadasoUserRoleController@browseAllRolebrowse_user_role
POST/user-roles/add-editBadasoUserRoleController@addOrEditadd_or_edit_user_role
GET/role-permissions/BadasoRolePermissionController@browseByRolebrowse_role_permission
GET/role-permissions/all-permissionBadasoRolePermissionController@browseAllPermissionbrowse_role_permission
POST/role-permissions/add-editBadasoRolePermissionController@addOrEditadd_or_edit_role_permission

Sinkronisasi role milik user

BadasoUserRoleController::addOrEdit menerima user_id dan array roles, lalu menyamakan isi pivot dengan daftar itu: setiap role yang dikirim disimpan lewat UserRole::firstOrCreate, dan baris yang tidak lagi ada di daftar dihapus lewat whereNotIn('role_id', $stored_roles) src/Controllers/BadasoUserRoleController.php:82-122. Model UserRole menyimpan user_id dan role_id sebagai fillable dan menyediakan relasi role() serta user() untuk memuat keduanya src/Models/UserRole.php:25-38.

graph TD
  A["POST /user-roles/add-edit"] --> B["validasi user_id"]
  B --> C["User::find"]
  C --> D["loop roles"]
  D --> E["Role::find"]
  E --> F["UserRole::firstOrCreate"]
  F --> G["stored_roles[]"]
  G --> H["whereNotIn role_id"]
  H --> I["UserRole::find->delete"]
  C --> J["activity User created or updated"]
  style A fill:#f59e0b,color:#000
  style F fill:#2d7d46,color:#fff
  style G fill:#8b5cf6,color:#fff
  style I fill:#dc2626,color:#fff
  style J fill:#336791,color:#fff
%% fig: Alur addOrEdit pada user_roles
%% desc: Role yang dikirim disimpan dengan firstOrCreate, lalu baris pivot yang tidak ada di daftar dihapus.
Fig. 2: Alur addOrEdit pada user_rolesRole yang dikirim disimpan dengan firstOrCreate, lalu baris pivot yang tidak ada di daftar dihapus.

⚠️ Handler ini bersifat mengganti, bukan menambah. Bila roles dikirim kosong, $stored_roles tetap kosong dan whereNotIn mencocokkan semua baris milik user itu, sehingga seluruh role user tersebut dicabut src/Controllers/BadasoUserRoleController.php:82-122. Handler juga tidak membungkus prosesnya dengan DB::beginTransaction, berbeda dari controller user, role, dan permission.

Untuk keperluan tampilan, browseAllRole tidak memakai relasi Eloquent melainkan query SQL mentah yang menyusun tabel roles dengan LEFT JOIN ke user_roles dan menambahkan kolom selected bernilai 1 atau 0 untuk user yang sedang dibuka src/Controllers/BadasoUserRoleController.php:54-80. Nama tabel di kedua sisi query memakai config('badaso.database.prefix'), jadi awalan tabel harus konsisten dengan konfigurasi.

Sinkronisasi permission milik role

BadasoRolePermissionController::addOrEdit adalah padanan langsung dari handler sebelumnya pada pivot role_permissions: permissions wajib diisi, tiap permission disimpan lewat RolePermission::firstOrCreate, dan baris yang tidak lagi dikirim dihapus dengan whereNotIn('permission_id', $stored_permissions) src/Controllers/BadasoRolePermissionController.php:78-121. Model RolePermission memakai fillable berisi id, role_id, dan permission_id, dengan relasi role() dan permission() src/Models/RolePermission.php:25-39.

⚠️ Berbeda dari BadasoUserRoleController@addOrEdit, handler ini memvalidasi permissions sebagai required. Request tanpa field itu gagal validasi, bukan diam-diam mengosongkan permission role src/Controllers/BadasoRolePermissionController.php:78-121.

Daftar permission untuk satu role diambil browseAllPermission dengan pola query yang sama seperti browseAllRole, hanya saja tabel yang di-join adalah permissions dan role_permissions src/Controllers/BadasoRolePermissionController.php:50-76.

Permission yang lahir dari nama tabel

Selain dibuat manual lewat BadasoPermissionController@add, permission dibuat otomatis oleh Permission::generateFor. Static method itu hanya bekerja bila belum ada permission dengan table_name tersebut, lalu membuat lima permission browse_, read_, edit_, add_, dan delete_ yang digabung dengan nama tabel, ditambah maintenance_ bila argumen $is_maintenance benar. Setiap permission baru langsung dihubungkan ke role administrator yang dicari dengan firstOrFail src/Models/Permission.php:27-57.

graph LR
  S["Permission::generateFor"] --> Q{"permission untuk table_name sudah ada?"}
  Q -- belum --> P["firstOrCreate browse_ read_ edit_ add_ delete_"]
  P --> M["maintenance_ bila is_maintenance"]
  M --> R["Role::where name administrator"]
  R --> RP["RolePermission role_id + permission_id"]
  Q -- sudah --> X["tidak ada perubahan"]
  style S fill:#f59e0b,color:#000
  style P fill:#2d7d46,color:#fff
  style RP fill:#336791,color:#fff
  style X fill:#8b5cf6,color:#fff
%% fig: Pembuatan permission otomatis per tabel
%% desc: generateFor membuat lima permission standar (plus maintenance) dan mengaitkannya ke role administrator.
Fig. 3: Pembuatan permission otomatis per tabelgenerateFor membuat lima permission standar (plus maintenance) dan mengaitkannya ke role administrator.

Kebalikannya, Permission::removeFrom menghapus semua permission yang table_name-nya cocok beserta baris RolePermission terkait src/Models/Permission.php:59-65. generateForTableCRUD menyapu seluruh DataType dan mengisi roles_can_see_all_data dengan ["administrator"] serta field_identify_related_user dengan user_id bila kedua kolom masih null src/Models/Permission.php:101-114. Pemanggilan generateFor dari alur CRUD dibahas di CRUD Generator dan Content Manager.

Pengelolaan user

BadasoUserController@add memvalidasi email, name, username, phone, dan gender sebagai wajib, dengan username dibatasi alpha_num dan harus unik. Password selalu di-hash memakai Hash::make, dan email_verified_at hanya diisi bila request mengirim email_verified src/Controllers/BadasoUserController.php:104-148. Pada edit, password hanya ditimpa bila field password benar-benar berisi nilai src/Controllers/BadasoUserController.php:75-80. Kolom yang boleh diisi massal didefinisikan di $fillable model User src/Models/User.php:34-45, sementara password dan remember_token disembunyikan dari serialisasi lewat $hidden src/Models/User.php:52-55.

Saat menghapus, BadasoUserController@delete memanggil handleDeleteFile($user->avatar) dari trait FileHandler sebelum baris user dihapus, sehingga berkas avatar tidak tertinggal src/Controllers/BadasoUserController.php:150-180. deleteMultiple mengulang langkah yang sama untuk setiap id pada parameter ids yang dipisah koma src/Controllers/BadasoUserController.php:150-180.

⚠️ deleteMultiple mencatat activity memakai variabel $user hasil iterasi terakhir, bukan kumpulan nama yang sudah dihimpun di $user_name, sehingga log hanya mewakili satu user src/Controllers/BadasoUserController.php:150-180.

Nama sebagai kunci unik

Role dan permission memakai nama sebagai identitas. Validasi edit pada role menolak name yang sudah dipakai role lain lewat aturan unique dengan pengecualian id yang sedang diedit, dan menyimpan name, display_name, serta description src/Controllers/BadasoRoleController.php:43-82. Pada permission, key menjadi kolom unik, sedangkan always_allow, is_public, table_name, roles_can_see_all_data, dan field_identify_related_user melengkapi aturan aksesnya src/Controllers/BadasoPermissionController.php:43-83.

⚠️ Mengubah name sebuah role memutus asumsi kode lain yang mencari role berdasarkan nama, seperti Role::where('name', 'administrator') di Permission::generateFor. Ganti nama role bawaan hanya setelah memastikan tidak ada pencarian berbasis nama yang tertinggal src/Models/Permission.php:27-57.

Ringkasan berkas

BerkasPeran
BadasoUserController.phpCRUD user, hash password, penghapusan avatar
BadasoRoleController.phpCRUD role dengan name unik
BadasoPermissionController.phpCRUD permission dengan key unik
BadasoUserRoleController.phpSinkronisasi pivot user_roles, daftar role per user
BadasoRolePermissionController.phpSinkronisasi pivot role_permissions, daftar permission per role
User.php, Role.php, Permission.phpRelasi belongsToMany dan pembuatan permission otomatis
UserRole.php, RolePermission.php, UserVerification.phpModel pivot dan token verifikasi