Như chúng ta đã biết role và permission là một phần rất quan trọng trong hầu hết các website hiện nay. Trong laravel hiện nay có rất nhiều package hỗ trợ cho việc này như ‘spatie/laravel-permission‘. Nhưng hôm nay mình sẽ chia sẻ với các bạn cách tạo role và permission đơn giản mà không cần dùng đến package. Chúng ta cùng thực hiện qua các bước sau nhé.
Bước 1. Tạo dự án laravel 8
- Tạo một dự án laravel (hiện tại bản mới nhất là 8.*) mới bằng câu lệnh sau, đồng thời bạn cũng vào trong file .env để config cho database dùng cho project này bao gồm tên database,
composer create-project --prefer-dist laravel/laravel Laravel_Role_Permission
- Để cài đặt theo vesion:
composer create-project --prefer-dist laravel/laravel:^8 Laravel_Role_Permission
- Trong file .env
DB_DATABASE= laravel_role_permissions //tên databaseDB_USERNAME= root //usernameDB_PASSWORD=//password
Bước 2: Tạo Auth
- Tạo laravel authentication bằng câu lệnh sau:
php artisan make:auth
Bước 3: Tạo Model và Migration
- Sau khi tạo xong dự án và auth, chúng ta cần tạo model cho roles và permissions.
php artisan make:model Permission -m
php artisan make:model Role -m
Bước 4: Sửa file migration
- Tạo Users table
publicfunctionup(){Schema::create('users',function(Blueprint$table){$table->id();$table->string('name');$table->string('email')->unique();$table->timestamp('email_verified_at')->nullable();$table->string('password');$table->rememberToken();$table->timestamps();});}
- Tạo Permissions Table
publicfunctionup(){Schema::create('permissions',function(Blueprint$table){$table->id();$table->string('name');$table->string('slug');$table->timestamps();});}
- Tạo Roles Table
publicfunctionup(){Schema::create('roles',function(Blueprint$table){$table->id();$table->string('name');$table->string('slug');$table->timestamps();});}
Bước 5: Thêm pivot table
- Chúng ta sẽ tạo bảng pivot users_permissions, sử dụng câu lệnh sau:
php artisan make:migration create_users_permissions_table --create=users_permissions
-Thay đổi bảng user_permissions như sau:
publicfunctionup(){Schema::create('users_permissions',function(Blueprint$table){$table->unsignedInteger('user_id');$table->unsignedInteger('permission_id');//FOREIGN KEY$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');$table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');//PRIMARY KEYS$table->primary(['user_id','permission_id']);});}publicfunctiondown(){Schema::dropIfExists('users_permissions');}
- Tiếp tục tạo bảng pivot users_roles, sử dụng câu lệnh sau :
php artisan make:migration create_users_roles_table --create=users_roles
- Thay đổi bảng users_roles như sau:
publicfunctionup(){Schema::create('users_roles',function(Blueprint$table){$table->unsignedInteger('user_id');$table->unsignedInteger('role_id');//FOREIGN KEY$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');//PRIMARY KEYS$table->primary(['user_id','role_id']);});}publicfunctiondown(){Schema::dropIfExists('users_roles');}
- Tạo thêm bảng roles_permissions. Bảng này được sử dụng để cấp quyền cho người dùng. Ví dụ, người dùng có quyền xem đối với bài đăng còn với tư cách là quản trị viên có quyền chỉnh sửa hoặc xóa bài đăng. Đó là nhiệm vụ của bảng này, sử dụng câu lệnh sau:
php artisan make:migration create_roles_permissions_table --create=roles_permissions
- Thay đổi bảng roles_permissions như sau:
publicfunctionup(){Schema::create('roles_permissions',function(Blueprint$table){$table->unsignedInteger('role_id');$table->unsignedInteger('permission_id');//FOREIGN KEY$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');$table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');//PRIMARY KEYS$table->primary(['role_id','permission_id']);});}publicfunctiondown(){Schema::dropIfExists('roles_permissions');}
- Run câu lệnh sau để tạo migration :
php artisan migrate
Bước 6: Tạo relationships
- Tạo quan hệ giữa hai bảng roles và permissions như sau:
- Trong file App/Role.php
publicfunctionpermissions(){return$this->belongsToMany(Permission::class,'roles_permissions');}publicfunctionusers(){return$this->belongsToMany(User::class,'users_roles');}
- Trong file App/Permission.php
publicfunctionroles(){return$this->belongsToMany(Role::class,'roles_permissions');}publicfunctionusers(){return$this->belongsToMany(User::class,'users_permissions');}
Bước 7: Tạo Trait
- Tạo một thư mục mới và đặt tên là Permissions và tạo một tên tệp mới HasPermissionsTrait.php. Đây là xử lý quan hệ người dùng. Trở lại trong model User chúng ta chỉ cần import trait này vào là được.
- Trong file app/User.php
namespaceApp;useAppPermissionsHasPermissionsTrait;classUserextendsAuthenticatable{useHasPermissionsTrait;//Import The Trait}
- Trong file HasPermissionsTrait.php
namespaceApp;useAppPermissionsHasPermissionsTrait;classUserextendsAuthenticatable{namespaceAppPermissions;useAppPermission;useAppRole;traitHasPermissionsTrait{publicfunctiongivePermissionsTo(...$permissions){$permissions=$this->getAllPermissions($permissions);if($permissions===null){return$this;}$this->permissions()->saveMany($permissions);return$this;}publicfunctionwithdrawPermissionsTo(...$permissions){$permissions=$this->getAllPermissions($permissions);$this->permissions()->detach($permissions);return$this;}publicfunctionrefreshPermissions(...$permissions){$this->permissions()->detach();return$this->givePermissionsTo($permissions);}publicfunctionhasPermissionTo($permission){return$this->hasPermissionThroughRole($permission)||$this->hasPermission($permission);}publicfunctionhasPermissionThroughRole($permission){foreach($permission->rolesas$role){if($this->roles->contains($role)){returntrue;}}returnfalse;}publicfunctionhasRole(...$roles){foreach($rolesas$role){if($this->roles->contains('slug',$role)){returntrue;}}returnfalse;}publicfunctionroles(){return$this->belongsToMany(Role::class,'users_roles');}publicfunctionpermissions(){return$this->belongsToMany(Permission::class,'users_permissions');}protectedfunctionhasPermission($permission){return(bool)$this->permissions->where('slug',$permission->slug)->count();}protectedfunctiongetAllPermissions(array$permissions){returnPermission::whereIn('slug',$permissions)->get();}}}
-Ở đây chúng ta có thể debug như sau để kiểm tra.
$user=$request->user();//getting the current logged in userdd($user->hasRole('admin','editor'));// and so on
Bước 8: Tạo custom Provider
- Trong bước này, chúng ta sử dụng lệnh Laravel directive “can” để kiểm tra xem User có quyền hay không thay vì sử dụng hàm $user-> hasPermissionTo ().
- Để sử dụng giống như $user-> can(), chúng ta cần tạo PermissionsServiceProvider mới để ủy quyền. Sử dụng câu lệnh sau:
php artisan make:provider PermissionsServiceProvider
- Đăng ký trong method boot như sau:
namespaceAppProviders;useAppPermission;useIlluminateSupportFacadesBlade;useIlluminateSupportFacadesGate;useIlluminateSupportServiceProvider;classPermissionsServiceProviderextendsServiceProvider{publicfunctionregister(){//}publicfunctionboot(){try{Permission::get()->map(function($permission){Gate::define($permission->slug,function($user)use($permission){return$user->hasPermissionTo($permission);});});}catch(Exception$e){report($e);returnfalse;}//Blade directivesBlade::directive('role',function($role){return"if(auth()->check() && auth()->user()->hasRole({$role})) :";//return this if statement inside php tag});Blade::directive('endrole',function($role){return"endif;";//return this endif statement inside php tag});}}
- Tiếp đến đăng ký PermissionsServiceProvider. Trong file app.php chúng ta làm như sau :
//configapp.php'providers'=>[AppProvidersPermissionsServiceProvider::class,],
- Bạn có thể test như sau:
dd($user->can('permission-slug'));
Bước 9: Tạo dữ liệu để test
- Tạo route:
Route::get('/roles',[PermissionController::class,'Permission']);
- Tạo AppHttpControllersPermissionController.php
namespaceAppHttpControllers;useAppPermission;useAppRole;useAppUser;useIlluminateHttpRequest;classPermissionControllerextendsController{publicfunctionPermission(){$user_permission=Permission::where('slug','create-tasks')->first();$admin_permission=Permission::where('slug','edit-users')->first();//RoleTableSeeder.php$user_role=newRole();$user_role->slug='user';$user_role->name='User_Name';$user_role->save();$user_role->permissions()->attach($user_permission);$admin_role=newRole();$admin_role->slug='admin';$admin_role->name='Admin_Name';$admin_role->save();$admin_role->permissions()->attach($admin_permission);$user_role=Role::where('slug','user')->first();$admin_role=Role::where('slug','admin')->first();$createTasks=newPermission();$createTasks->slug='create-tasks';$createTasks->name='Create Tasks';$createTasks->save();$createTasks->roles()->attach($user_role);$editUsers=newPermission();$editUsers->slug='edit-users';$editUsers->name='Edit Users';$editUsers->save();$editUsers->roles()->attach($admin_role);$user_role=Role::where('slug','user')->first();$admin_role=Role::where('slug','admin')->first();$user_perm=Permission::where('slug','create-tasks')->first();$admin_perm=Permission::where('slug','edit-users')->first();$user=newUser();$user->name='Test_User';$user->email='[email protected]';$user->password=bcrypt('1234567');$user->save();$user->roles()->attach($user_role);$user->permissions()->attach($user_perm);$admin=newUser();$admin->name='Test_Admin';$admin->email='[email protected]';$admin->password=bcrypt('admin1234');$admin->save();$admin->roles()->attach($admin_role);$admin->permissions()->attach($admin_perm);returnredirect()->back();}}
- Chạy url route bạn có thể nhìn thấy một số dữ liệu giả từ các bảng.
$user=$request->user();dd($user->hasRole('user'));//sẽ return true, nếu user có roledd($user->givePermissionsTo('create-tasks'));// sẽ return về permission, không thì trả về nulldd($user->can('create-tasks'));// sẽ return true, nếu user có permission
- Trong file blade bạn có thể dùng nó như sau:
@role('user')
This is user role
@endrole
@role('admin')
This is admin role
@endrole
- Bạn có thể sử dụng nhiều role nếu bạn muốn.
Bước 10: Cài đặt Middleware
- Sử dụng câu lệnh sau:
php artisan make:middleware RoleMiddleware
- Để add middleware vào file kernel và setup như sau:
- Trong file AppHttpMiddlewareRoleMiddleware.php
namespaceAppHttpMiddleware;useClosure;classRoleMiddleware{publicfunctionhandle($request,Closure$next,$role,$permission=null){if(!$request->user()->hasRole($role)){abort(404);}if($permission!==null&&!$request->user()->can($permission)){abort(404);}return$next($request);}}
- Đăng ký RoleMiddleware vào file Kernel.php
- AppHttpKernel.php
protected$routeMiddleware=['role'=>AppHttpMiddlewareRoleMiddleware::class,];
- Và bây giờ trong file routes chúng ta đã có thể sử dụng:
Route::group(['middleware'=>'role:user'],function(){Route::get('/user',function(){return'Welcome...!!';});});
- Bây giờ bạn có thể sử dụng trong Controller của mình như bên dưới để cấp quyền và truy cập cho người dùng.
publicfunction__construct(){$this->middleware('auth');}publicfunctionstore(Request$request){if($request->user()->can('create-tasks')){...}}publicfunctiondestroy(Request$request,$id){if($request->user()->can('delete-tasks')){...}}
- Các kiến thức các bạn có thể tìm hiểu thêm
- Laravel Gate facade at Laravel Documentation.
- Trait trong php.
** TRÊN ĐÂY LÀ NHỮNG CHIA SẺ CỦA MÌNH, CẢM ƠN CÁC BẠN ĐÃ ĐỌC BÀI VIẾT .**😘
Nguồn: viblo.asia