Yêu cầu đặt ra là tạo một trang admin có chức năng phân quyền, các role cơ bản: super-admin, admin, client ... tương ứng với mỗi role sẽ có các quyền(permissions) khác nhau. Để giải quyết yêu cầu này hôm nay chúng ta cùng tìm hiểu laravel-permission một package phân quyền nhanh và đơn giản viết cho laravel framework.
Laravel permission cho phép chúng ta có thể dễ dàng phân chia các vai trò (roles) và quyền (permissions) dùng để quản lý quyền hạn truy cập trong một trang web.
1. Sử dụng laravel phiên bản lớn hơn hơn 5.8
2. Nếu source code đã có file config/permission.php
bạn phải đổi tên hoặc xóa nó đi, bởi vì khi setup thì package tạo ra file config/permission.php
3. Cài đặt package với composer
composer require spatie/laravel-permission
4. Đăng kí service provider: service provider sẽ được đăng kí tự động or đăng kí bằng tay tuỳ phiên bản laravel, đăng kí service provider trong config/app.php
'providers' => [
// ...
Spatie\Permission\PermissionServiceProvider::class,
];
5. Tạo migration và config permisstion
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
6. Clear config cache
php artisan optimize:clear
# or
php artisan config:clear
7. Tạo các bảng phân quyền
php artisan migrate
Khi chạy xong command trên các bảng sau sẽ được tạo ra:
roles: Quản lí các vai trò của người dùng(nhóm quyền): super-admin, admin, client
permissions: Quản lí các quyền truy cập vào ứng dụng: list-user, create_user, show_user, update_user, delete_user ...
role_has_permissions: Quản lí các quyền được gán cho 1 role
model_has_roles: Quản lí các role được gán cho 1 user
model_has_permissions: Quản lí các quyền được gán cho 1 user
8. Thêm trait phân quyền cho model sử dụng đăng nhập admin
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
// ...
}
Như vậy là bạn đã cài đặt và config xong package laravel permission rồi đó, thật đơn giản phải không, giờ thì sử dụng nó thôi nào :D
1. Tạo role, permission
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);
2. Gán permission cho role
$role->givePermissionTo($permission);
$permission->assignRole($role);
3. Đồng bộ hoá permissions cho role
Các permission được gán cho role đúng bằng mảng các permission truyền vào, không bị lặp lại permission khi gán nhiều lần.
$role->syncPermissions($permissions);
$permission->syncRoles($roles);
4. Xoá quyền khỏi role
$role->revokePermissionTo($permission);
$permission->removeRole($role);
5. Gán role cho user
$user->assignRole('writer');
// You can also assign multiple roles at once
$user->assignRole('writer', 'admin');
// or as an array
$user->assignRole(['writer', 'admin']);
6. Đồng bộ hoá role cho user
Các role được gán cho user đúng bằng mảng các role truyền vào, không bị lặp lại role khi gán nhiều lần.
$user->syncRoles(['super-admin', 'admin']);
7. Xoá role khỏi user
$user->removeRole('writer');
8. Gán permission trực tiếp cho user
$user->givePermissionTo($permission);
$user->givePermissionTo(array $permissions);
9. Xoá permission khỏi user
$user->revokePermissionTo($permission);
10. Đồng bộ permission với user
$user->syncPermissions(array $permissions);
// Get roles of user
$user->getRoleNames();
// Get permission thông qua role
$user->getPermissionsViaRoles()->pluck('name')->toArray();
// Get all permissions asign directly to user
$permissions = $user->getDirectPermissions();
// Get all permissions asign to user
$permissions = $user->getAllPermissions();
// check user can edit articles
$user->can('edit articles');
// Check permission in blade
@can('edit articles')
...
@endcan
// Check user has permission
$user->hasPermissionTo($permissionName);
$user->hasPermissionTo(int $permissionId);
// Kiểm tra user có 1 trong các quyền
$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);
// Kiểm tra user phải có tất cả các quyền
$user->hasAllPermissions(['edit articles', 'publish articles', 'unpublish articles']);
Default middleware
// Chỉ cho phép user có quyền publish articles được truy cập
Route::group(['middleware' => ['can:publish articles']], function () {
//
});
Package middleware thêm các middleware vào file app/Http/Kernel.php
để sử dụng
protected $routeMiddleware = [
// ...
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];
// Chỉ user có role super-admin mới được truy cập
Route::group(['middleware' => ['role:super-admin']], function () {
//
});
// Chỉ user có quyền publish articles mới được truy cập
Route::group(['middleware' => ['permission:publish articles']], function () {
//
});
Giờ chúng ta cùng viết 1 ứng dụng phân quyền nhé
1. Tạo file config các role permission
<?php
return [
'super_admin' => [
'roles' => [
'name' => 'super-admin',
],
],
'admin' => [
'roles' => [
'name' => 'admin',
],
'permissions' => [
'list_article',
'show_article',
'update_article',
'list_image',
'show_image',
'update_image',
'create_image',
'delete_image',
],
],
'client' => [
'roles' => [
'name' => 'client',
],
'permissions' => [
'list_article',
'list_image',
'show_image',
'update_image',
'create_image',
'delete_image',
],
],
];
2. Tạo seeding user role super-admin
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use App\Models\User;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$countUser = User::count();
if (!$countUser) {
// Create user
$user = User::create(['name' => 'super-admin']);
// Create role super_admin
Role::create(config('roles.super_admin.roles'));
// Assign role super admin to user
$user->assignRole(config('roles.super_admin.roles'));
}
}
}
3. Seeding tạo các role admin, client và gán các quyền tương ứng cho role
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class PermissionSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Add admin role
$adminRole = Role::where('name', config('roles.admin.roles'))->first();
if (!$adminRole) {
$adminRole = Role::create(config('roles.admin.roles'));
}
// Get new admin permission
$newPermissions = $this->getNewPermissions('roles.admin.permissions');
Permission::insert($newPermissions);
$adminRole->syncPermissions(config('roles.admin.permissions'));
// Add client role
$clientRole = Role::where('name', config('roles.client.roles'))->first();
if (!$clientRole) {
$clientRole = Role::create(config('roles.client.roles'));
}
// Get new client permission
$newPermissions = $this->getNewPermissions('roles.client.permissions');
Permission::insert($newPermissions);
$clientRole->syncPermissions(config('roles.client.permissions'));
}
/**
* Get list new permissions from file config
* @param string $config
* @return array
*/
private function getNewPermissions(string $config): array
{
$currentPermissions = Permission::get('name')->pluck('name')->toArray();
$newPermissions = [];
$configPermissions = config($config);
foreach ($configPermissions as $configPermission) {
if (!in_array($configPermission, $currentPermissions)) {
$newPermissions[] = [
'name' => $configPermission,
'guard_name' => config('auth.guards.admin'),// config guard for admin
'created_at' => now(),
'updated_at' => now(),
];
}
}
return $newPermissions;
}
}
như vậy là đã seeding xong user, role, permission nhé
// Kiểm tra quyền thêm
$api->post('articles', 'ArticlesController@store')->middleware('permission:create_article');
// Kiểm tra quyền xem list
$api->get('articles', 'ArticlesController@index')->middleware('permission:list_article');
// Kiểm tra quyền xem chi tiết
$api->get('articles/{id}', 'ArticlesController@show')->middleware('permission:show_article');
// Kiểm tra quyền xoá
$api->delete('articles/{id}', 'ArticlesController@destroy')->middleware('permission:delete_article');
// Kiểm tra quyền sửa
$api->put('articles/{id}', 'ArticlesController@update')->middleware('permission:update_article');
Như vậy là chúng ta đã tìm hiểu và demo xong một ứng dụng phân quyền nhỏ, chúc các bạn phân quyền thành công :D