Roles and sanctions are a paramount part of many web applications. In this tutorial, we will optically discern how we can implement utilizer roles and sanctions system in laravel. We will optically discern it from scratch. We won't utilize spatie/laravel-sanction package for doing it. But you can utilize spatie/laravel-sanction to engender this roles and sanctions system in laravel 7.
read also User Roles and Permissions using Spatie
It is consequential to integrate laravel utilizer roles and sanctions mechanism in our immensely colossal scale application to give the sanction to utilizer to categorical task. We will visually perceive from scratch laravel 7/6 utilizer roles and sanctions tutorial.
If you don't ken how to engender laravel 7/6 roles and sanctions, then you are a right place. I will edify you from scratch laravel roles and sanctions.But in this tutorial we will do utilizer roles and sanctions in laravel utilizing our own custom code. So let's commence how to implement & setup roles and sanctions in Laravel.
I updated this tutorial for laravel 7/6 version. So if you face any error, then you can check git repository.
Open up your terminal and create a new Laravel project by typing in the following command
composer create-project --prefer-dist laravel/laravel rolePermissionDemo
If you are using laravel version 6 then run below command to make auth
composer require laravel/ui --dev
php artisan ui vue --auth
npm install
npm run watch
If you are using below laravel version 6 then run below command to make auth
php artisan make:auth
We need model to make users roles and permissions. So let's create our model using below command.
php artisan make:model Permission -m
php artisan make:model Role -m
As you may know, -m flag will create a migration file for the model. Now you’ll have two new migration files waiting for you to add new fields.
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email',191)->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePermissionsTable extends Migration
{
public function up()
{
Schema::create('permissions', function (Blueprint $table) {
$table->increments('id');
$table->string('name'); // edit posts
$table->string('slug'); //edit-posts
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('permissions');
}
}
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRolesTable extends Migration
{
public function up()
{
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name'); // edit posts
$table->string('slug'); //edit-posts
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('roles');
}
}
For this first pivot table, we’ll create a new migration file for the table users_permissions. So run below command to create
php artisan make:migration create_users_permissions_table --create=users_permissions
For this pivot table between users and permissions, our schema should look like
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersPermissionsTable extends Migration
{
public function up()
{
Schema::create('users_permissions', function (Blueprint $table) {
$table->unsignedInteger('user_id');
$table->unsignedInteger('permission_id');
//FOREIGN KEY CONSTRAINTS
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
//SETTING THE PRIMARY KEYS
$table->primary(['user_id','permission_id']);
});
}
public function down()
{
Schema::dropIfExists('users_permissions');
}
}
Now let’s create a pivot table for users_roles.
php artisan make:migration create_users_roles_table --create=users_roles
The fields inside this table will pretty much the same as in users_permissions table. Our schema for this table will look like:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersRolesTable extends Migration
{
public function up()
{
Schema::create('users_roles', function (Blueprint $table) {
$table->unsignedInteger('user_id');
$table->unsignedInteger('role_id');
//FOREIGN KEY CONSTRAINTS
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
//SETTING THE PRIMARY KEYS
$table->primary(['user_id','role_id']);
});
}
public function down()
{
Schema::dropIfExists('users_roles');
}
}
Under a particular Role, User may have specific Permission
For example, a user may have the permission for post a topic, and an admin may have the permission to edit or delete a topic. In this case, let’s setup a new table for roles_permissions to handle this complexity.
php artisan make:migration create_roles_permissions_table --create=roles_permissions
The Schema will be like:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRolesPermissionsTable extends Migration
{
public function up()
{
Schema::create('roles_permissions', function (Blueprint $table) {
$table->unsignedInteger('role_id');
$table->unsignedInteger('permission_id');
//FOREIGN KEY CONSTRAINTS
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
$table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
//SETTING THE PRIMARY KEYS
$table->primary(['role_id','permission_id']);
});
}
public function down()
{
Schema::dropIfExists('roles_permissions');
}
}
Now run following command to create migration
php artisan migrate
We’ll start by creating the relationships between roles and permissions table. In our Role.php , Permision.php.
App/Role.php
public function permissions() {
return $this->belongsToMany(Permission::class,'roles_permissions');
}
public function users() {
return $this->belongsToMany(User::class,'users_roles');
}
App/Permission.php
public function roles() {
return $this->belongsToMany(Role::class,'roles_permissions');
}
public function users() {
return $this->belongsToMany(User::class,'users_permissions');
}
Inside of our app directory, let’s create a new directory and name it as Permissions and create a new file namely HasPermissionsTrait.php. A nice little trait has been setup to handle user relations. Back in our User model, just import this trait and we’re good to go.
app/User.php
namespace App;
use App\Permissions\HasPermissionsTrait;
class User extends Authenticatable
{
use HasPermissionsTrait; //Import The Trait
}
Now open HasPermissionsTrait.php and paste those following code.
App/Permissions/HasPermissionsTrait.php
namespace App\Permissions;
use App\Permission;
use App\Role;
trait HasPermissionsTrait {
public function givePermissionsTo(... $permissions) {
$permissions = $this->getAllPermissions($permissions);
dd($permissions);
if($permissions === null) {
return $this;
}
$this->permissions()->saveMany($permissions);
return $this;
}
public function withdrawPermissionsTo( ... $permissions ) {
$permissions = $this->getAllPermissions($permissions);
$this->permissions()->detach($permissions);
return $this;
}
public function refreshPermissions( ... $permissions ) {
$this->permissions()->detach();
return $this->givePermissionsTo($permissions);
}
public function hasPermissionTo($permission) {
return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission);
}
public function hasPermissionThroughRole($permission) {
foreach ($permission->roles as $role){
if($this->roles->contains($role)) {
return true;
}
}
return false;
}
public function hasRole( ... $roles ) {
foreach ($roles as $role) {
if ($this->roles->contains('slug', $role)) {
return true;
}
}
return false;
}
public function roles() {
return $this->belongsToMany(Role::class,'users_roles');
}
public function permissions() {
return $this->belongsToMany(Permission::class,'users_permissions');
}
protected function hasPermission($permission) {
return (bool) $this->permissions->where('slug', $permission->slug)->count();
}
protected function getAllPermissions(array $permissions) {
return Permission::whereIn('slug',$permissions)->get();
}
}
Here, we’re iterating through the roles and checking by the slug field, if that specific role exists. You can check or debug this by using:
$user = $request->user(); //getting the current logged in user
dd($user->hasRole('admin','editor')); // and so on
We’ll be utilizing the Laravel’s “can” directive to check if the User have Permission. and instead of using $user->hasPermissionTo().
we’ll use $user->can() To do so, we need to create a new PermissionsServiceProvider for authorization
php artisan make:provider PermissionsServiceProvider
Register your service provider and head over to the boot method to provide us a Gateway to use can() method.
namespace App\Providers;
use App\Permission;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
class PermissionsServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
try {
Permission::get()->map(function ($permission) {
Gate::define($permission->slug, function ($user) use ($permission) {
return $user->hasPermissionTo($permission);
});
});
} catch (\Exception $e) {
report($e);
return false;
}
//Blade directives
Blade::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
});
}
}
now we have to register our PermissionsServiceProvider. Open this following file add this in providers array.
config\app.php
'providers' => [
App\Providers\PermissionsServiceProvider::class,
],
You can learn more about Laravel’s Gate facade at Laravel’s documentation. You can test it out as:
dd($user->can('permission-slug'));
For creating roles and permissions tutorial, we need dummy data to check our user access. To create it paste this following code into this followng slug.
Route::get('/roles', '[email protected]');
App\Http\Controllers\PermissionController.php
namespace App\Http\Controllers;
use App\Permission;
use App\Role;
use App\User;
use Illuminate\Http\Request;
class PermissionController extends Controller
{
public function Permission()
{
$dev_permission = Permission::where('slug','create-tasks')->first();
$manager_permission = Permission::where('slug', 'edit-users')->first();
//RoleTableSeeder.php
$dev_role = new Role();
$dev_role->slug = 'developer';
$dev_role->name = 'Front-end Developer';
$dev_role->save();
$dev_role->permissions()->attach($dev_permission);
$manager_role = new Role();
$manager_role->slug = 'manager';
$manager_role->name = 'Assistant Manager';
$manager_role->save();
$manager_role->permissions()->attach($manager_permission);
$dev_role = Role::where('slug','developer')->first();
$manager_role = Role::where('slug', 'manager')->first();
$createTasks = new Permission();
$createTasks->slug = 'create-tasks';
$createTasks->name = 'Create Tasks';
$createTasks->save();
$createTasks->roles()->attach($dev_role);
$editUsers = new Permission();
$editUsers->slug = 'edit-users';
$editUsers->name = 'Edit Users';
$editUsers->save();
$editUsers->roles()->attach($manager_role);
$dev_role = Role::where('slug','developer')->first();
$manager_role = Role::where('slug', 'manager')->first();
$dev_perm = Permission::where('slug','create-tasks')->first();
$manager_perm = Permission::where('slug','edit-users')->first();
$developer = new User();
$developer->name = 'Harsukh Makwana';
$developer->email = '[email protected]';
$developer->password = bcrypt('harsukh21');
$developer->save();
$developer->roles()->attach($dev_role);
$developer->permissions()->attach($dev_perm);
$manager = new User();
$manager->name = 'Jitesh Meniya';
$manager->email = '[email protected]';
$manager->password = bcrypt('jitesh21');
$manager->save();
$manager->roles()->attach($manager_role);
$manager->permissions()->attach($manager_perm);
return redirect()->back();
}
}
Now goto this url and hit enter on your keyboard. Then you will see some dummy data to those following tables. To test this out in your routes files, we can die and dump on:
$user = $request->user();
dd($user->hasRole('developer')); //will return true, if user has role
dd($user->givePermissionsTo('create-tasks'));// will return permission, if not null
dd($user->can('create-tasks')); // will return true, if user has permission
Inside of our view files, we can use it like:
@role('developer')
Hello developer
@endrole
This means only those user can see it whose role are developer. Now you can use many role as you want.
In order to protect our routes, we can setup the middleware to do so.
php artisan make:middleware RoleMiddleware
Add the middleware into your kernel & setup the handle method as follows
App\Http\Middleware\RoleMiddleware.php
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
public function handle($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);
}
}
Now we have to register this RoleMiddleware. So add this following code to register it.
App\Http\Kernel.php
protected $routeMiddleware = [
.
.
'role' => \App\Http\Middleware\RoleMiddleware::class,
];
Right now in our routes, we can do something like this
Route::group(['middleware' => 'role:developer'], function() {
Route::get('/admin', function() {
return 'Welcome Admin';
});
});
Now you can use your controller like below to give user permission and access.
public function __construct()
{
$this->middleware('auth');
}
public function store(Request $request)
{
if ($request->user()->can('create-tasks')) {
//Code goes here
}
}
public function destroy(Request $request, $id)
{
if ($request->user()->can('delete-tasks')) {
//Code goes here
}
}
i hope you like this article.
Hi, My name is Harsukh Makwana. i have been work with many programming language like php, python, javascript, node, react, anguler, etc.. since last 5 year. if you have any issue or want me hire then contact me on [email protected]
Angular 8|9 File Upload with Progress Bar Tutorial
Today we are going to learn how to uploa...How to loop through an array in JavaScript
Use the JavaScript for Loop...Force Redirect Website URL http to https in Laravel8
In this article, I will share with you h...Laravel 8 Sanctum API Authentication Tutorial
In this example, you will learn laravel...Laravel full calendar tutorial example using maddhatter/laravel-fullcalendar
In this post we are share with you how t...