Tidak seperti pada Symfony, CakePHP, Phalcon, Yii atau Zend Framework, dll; pada Laravel dan Lumen tidak ada built-in fitur seperti ACL, MAC, DAC, RBAC atau apapun itu namanya. Beberapa package memang tersedia untuk menangani hal ini seperti Sentry, Entrust, dll.
Pengalaman terakhir saya dengan beberapa packages tersebut lumayan jelek. Seperti misalnya setelah menggunakan Sentry ntah kenapa menjadi terasa lebih lambat. Dan Sentry ini sudah tidak di-update lagi oleh pembuatnya Cartalyst. Melainkan digantikan dengan Sentinel.
Pengalaman lagi dengan Entrust di Laravel 4. Saat itu Entrust v1 masih menggunakan “versi development” dari Ardent sebagai dependency-nya. Hal itu membuat banyak masalah. Apalagi saya menggunakan mininum-stability: "stable"
pada composer.json
.
Membuat Access Control sendiri
Disini saya akan bahas bagaimana membuat access control sederhana. Saya akan fokus pada kesederhanaan, agar anda bisa mengerti hal basic pada access control. Tentu saja anda bisa modifikasi sendiri sesuai dengan kebutuhkan anda nantinya.
Migrations
Untuk membuat ACL sendiri caranya dengan membuat migrations/table schema
// roles $table->increments('id'); $table->string('name');
// role_user $table->unsignedInteger('user_id'); $table->unsignedInteger('role_id'); $table->primary(['user_id', 'role_id']);
Relationship
Setelah itu kita buat relasi dengan menggunakan Eloquent.
<?php namespace App; // ... use Illuminate\Database\Eloquent\Model; class User extends Model { // ... public function roles() { return $this->belongsToMany('Role'); } // ... }
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Role extends Model { // ... public function users() { return $this->belongsToMany('User'); } // ... }
Fitur Role Assignment/Revoke
Tambahkan fitur untuk assign atau revoke role.
<?php namespace App; // ... use Illuminate\Database\Eloquent\Model; class User extends Model { // ... public function roles() { return $this->belongsToMany('Role'); } public function assignRole($role) { if (is_string($role)) { $role = Role::where('name', $role)->first(); } return $this->roles()->attach($role); } public function revokeRole($role) { if (is_string($role)) { $role = Role::where('name', $role)->first(); } return $this->roles()->detach($role); } // ... }
Fitur Pengecekan Role
<?php namespace App; // ... use Illuminate\Database\Eloquent\Model; class User extends Model { // ... public function roles() { return $this->belongsToMany('Role'); } public function assignRole($role) { if (is_string($role)) { $role = Role::where('name', $role)->first(); } return $this->roles()->attach($role); } public function revokeRole($role) { if (is_string($role)) { $role = Role::where('name', $role)->first(); } return $this->roles()->detach($role); } public function hasRole($name) { foreach($this->roles as $role) { if ($role->name === $name) return true; } return false; } // ... }
Dan sudah selesai 😐
Percaya atau tidak, membuat ini sebenernya cuma butuh waktu sekitar 2-6 menit 😐
Cara menggunakan
$user = User::find(1); // Jadikan user ini sebagai admin $user->assignRole('admin'); // Keluarkan user ini dari admin $user->revokeRole('admin');
Contoh pada controller untuk mengecek apakah current user memiliki role admin
if (Auth::user()->hasRole('admin')) { return Redirect::to('/backend'); }
Contoh pengecekan menu di view
@if (Auth::user()->hasRole('moderator')) <a href="#">Go to Backend</a> @endif
Middleware dan Filter
Filter
Jika anda menggunakan Laravel 4, anda bisa menggunakan filter. Letakkan ini pada app/filters.php
Route::filter('role', function($name) { if (Auth::check() && ! Auth::user()->hasRole($name)) { return App::abort(401, 'Unauthorized'); } });
Cara menggunakan filter di route
Route::get('/backend', [ 'uses' => 'BackendController@index', 'before' => 'role:admin' ]);
Middleware (Laravel 5.0)
Berhubung fitur middleware parameter belum ada di Laravel 5.0, anda bisa menggunakan filter. Karena filter sebenarnya tidak dihilangkan dari core Laravel 5.0. Anda bisa menggunakannya seperti di Laravel 4 seperti biasa.
Middleware (Laravel 5.1)
Buat middleware baru
./artisan make:middleware RoleMiddleware
Edit App\Http\Middleware\RoleMiddleware.php
public function handle($request, Closure $next, $roleName) { if (auth()->check() && ! auth()->user()->hasRole($roleName)) { return abort(401, 'Unauthorized'); } return $next($request); }
Di App\Http\Kernel.php
daftarkan middleware ini
protected $routeMiddleware = [ // ... 'role' => 'App\Http\Middleware\RoleMiddleware', ];
Cara menggunakan di route
Route::get('/backend', [ 'uses' => 'BackendController@index', 'middleware' => 'role:admin', ]);
Kesimpulan
Membuat fitur access control itu sangat mudah. Anda bisa menambahkan fitur-fitur lain seperti “permissions”, multiple role check:
Auth::user()->hasRole(['admin', 'operator', 'moderator']); // atau Auth::user()->hasRole('admin', 'operator', 'moderator'); dengan
Atau fitur-fitur lainnya yang anda butuhkan. Sehingga anda tidak mentok karena bergantung terhadap suatu package.
Jika ada pertanyaan silahkan tanyakan pada kolom komentar.
UPDATE 24 Juni 2015
Contoh code bisa dilihat di https://github.com/mul14/laravel-acl-demo
UPDATE 25 September 2015
Tambahin pengecekan string pada assignRole()
dan revokeRole()
, juga update source code di GitHub https://github.com/mul14/laravel-acl-demo
Memang TOP!
memang mantap
awesome
hmm sampai sekarang masih penasaran magic dibalik method attach(), kok bisa tau role ini idnya berapa 😮
Cuma pengecekan code sederhana aja, gak ada yang spesial.
Kalau model, maka ambil ID-nya.
iya kalau attachnya pakai model atau . misal yg diatas kan pake string ‘admin’, nah gimana bisa tau id dari row yang kolom ‘name’-nya adalah ‘admin’ ini. apa dicari semua kolom gitu? ini yg masih saya belum paham om. 😐
Kan ada table ketiga yang menghubungkan antara `users` dan `roles`, yaitu `role_user`. Coba cek migration-nya.
Ah yaa, akhirnya setelah ditanyakan ulang di Slack, saya ngerti maksudnya. Ternyata saya yang salah. Segera di-update artikel dan source code di GitHub.
maaf saya masih awam dengan laravel, mau tanya, untuk menempatkan
$user = User::find(1);
// Jadikan user ini sebagai admin
$user->assignRole(‘admin’);
// Keluarkan user ini dari admin
$user->revokeRole(‘admin’);
di bagian mana ya ?
Oh, ini cuma contoh untuk menggunakan. Nantinya terserah diletakkan dimana, tergantung dengan kebutuhan. Biasanya sih pada suatu proses dimana user tersebut mau dijadikan admin.
Tapi untuk belajar, atau cuma untuk nge-test, bisa diletakkan di
app/Http/routes.php
. Misalnya berisi:Lalu cek di database, table
role_user
, jika ada bertambah isinya, berarti berhasil. Begitu juga denganrevokeRole()
, kalau datanya hilang, berarti sudah berhasil.mas mau tanya, ketika saya $user->assignRole(‘admin’) lalu saya check hasilnya selelu false kenapa ya? saya coba pake https://github.com/romanbican/roles juga false.
mohon pencerahanya 😀
Wah 😐
Saya juga bingung kalo gak liat code-nya langsung. Mungkin ada yang kelewat. Coba aja pelajari ini https://github.com/mul14/laravel-acl-demo
ok mas udah bisa, mau tanya lagi agak menyimpang dari pembahasan 😀
akhirnya saya pake https://github.com/romanbican/roles , lalu cara pake di routenya bagaimana? saya pake Route::resource() 😀
Wah, saya nggak pernah pake itu 😐
Bikin sendiri lebih gampang. Apalagi sejak di Laravel 5.1.11 selain authentication sudah ada authorization.
http://laravel.com/docs/5.1/authorization
Mas, bagaimana cara menampilkan role name yang telah dipakai oleh user, untuk ditampilkan pada view. ? Terima kasih
Oh, gampang banget itu. Coba deh pake
dd()
diAuth::user()
. Kan keliatan kalau itu adalah object dariApp\User
. Berarti bisa pake semua yang ada di dalam class-nya. Kan di dalamnya sudah adaBerarti, cara manggilnya cukup dengan
Alhamdulillah,.. akhirnya bisa mas,… ^_^ terima kasih Mas.. saya udah mengerti sekarang. Ternyata saya yg salah persepsi ttg konsepnya mas. Jadi sebenernya saya ini kan lagi mengimplementasikan multiple auth dan authorization di Laravel 5.2, awalnya saya memanggil sesuai dgn konsepnya multiple auth, yaitu
{{ auth('user')->user()->role()->name }}
tapi kenapa selalu undefined property: padahal saya tau udah ada function role() di User model yg berelasi dgn Role model.. akhirnya saya berpikir cara lain dgn memanfaatkan pivot table role_user, tapi tetep sama aja… ^_^.utk melakukan validasi di controller
saya menggunakan
dapat berjalan dengan baik..
kalau ingin memvalidasi 2 role bukannya cukup seperti dibawah?
ato code diatas ada yang perlu diubah?