User Roles And Permissions Without Package Laravel 9

In this article, we will see user roles and permissions without a package in laravel 9. Here, we will learn how to create roles and permissions in laravel 9. Roles and permissions are an important part of many websites.

In this laravel 9 user roles and permissions example, we are not using any type of package like /laravel-permission for user roles permissions in laravel. But you can use /laravel-permission to create user roles and permissions tutorial in laravel 9.

So, let's see Laravel 9 user roles and permissions without a package.

Step 1: Install Laravel 9 App

Step 2: Create Laravel Auth

Step 3: Create a Model and Migration

Step 4: Edit Migration Files

Step 5: Add Pivot Tables

Step 6: Setting up the Relationships

Step 7: Create Trait

Step 8:  Create CustomProvider

Step 9: Add Dummy Data

Step 10: Setup the Middleware

 

Step 1: Install Laravel 9 App

In this step, we will install the laravel 9 application using the below command.

composer create-project --prefer-dist laravel/laravel laravel_9_user_role_permission

 

 

Step 2: Create Laravel Auth

In this step, we will create laravel authentication using the below command.

php artisan make:auth

 

Step 3: Create a Model and Migration

After creating the auth and project setup. We need to create a model for user's roles and permissions. So, let's create a model using the below command.

php artisan make:model Permission -m
php artisan make:model Role -m

 

Step 4: Edit Migration Files

UsersTable:

public function up()
{
        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();
        });
}

PermissionsTable:

public function up()
{
    Schema::create('permissions', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('slug');
        $table->timestamps();
    });
}

RolesTable:

public function up()
{
    Schema::create('roles', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('slug');
        $table->timestamps();
    });
}

 

 

Step 5: Add Pivot Tables

Now, we will create a users_permissions pivot tableSo, create a new migration file for the table using the below command.

php artisan make:migration create_users_permissions_table --create=users_permissions

Now, edit the user_permissions table and FOREIGN KEY between the users and permissions table.

public function up()
{
    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']);
    });
}

public function down()
{
    Schema::dropIfExists('users_permissions');
}

Now, we are creating a pivot table for the users_roles table.

php artisan make:migration create_users_roles_table --create=users_roles

Now, edit the users_roles table and FOREIGN KEY between the users and permissions table.

public function up()
{
    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']);
    });
}

public function down()
{
    Schema::dropIfExists('users_roles');
}

Now, create a roles_permissions table. This table is used to give permission to the user. For eg., Users have view permission for posts and the admin has permission to edit or delete posts. So, in this type of case, we need this table.

php artisan make:migration create_roles_permissions_table --create=roles_permissions

Edit the roles_permissions table and add a FOREIGN KEY between the roles and permissions table.

public function up()
{
    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']);
    });
}

public function down()
{
    Schema::dropIfExists('roles_permissions');
}

Now, run the following command to create a migration

php artisan migrate

 

 

Step 6: Setting up the Relationships

Now, we are creating the relationships between the roles and permissions table.

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');
       
}

 

Step 7: Create Trait

let’s create a new directory named it Permissions and create a new file named HasPermissionsTrait.php. This handles user relations and back in our User model, just we need to import this trait on the User Model.

app/User.php

namespace App;

use App\Permissions\HasPermissionsTrait;

class User extends Authenticatable
{
    use HasPermissionsTrait; //Import The Trait
}

Now open HasPermissionsTrait.php and add the below code in this file.

 

 

App/Permissions/HasPermissionsTrait.php

namespace App\Permissions;

use App\Permission;
use App\Role;

trait HasPermissionsTrait {

   public function givePermissionsTo(... $permissions) {

    $permissions = $this->getAllPermissions($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, 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

 

 

Step 8:  Create CustomProvider

In this step, we are using the Laravel “can” directive to check if the User has Permission or not, and instead of using the $user->hasPermissionTo() function.

Like us, $user->can(). So, we need to create a new PermissionsServiceProvider for authorization. copy the below command and create a service provider.

php artisan make:provider PermissionsServiceProvider

Register your service provider and head over to the boot method to provide us a Gateway to use the 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 need to register our PermissionsServiceProvider. In the app.php file add the below code.

config\app.php

'providers' => [

        App\Providers\PermissionsServiceProvider::class,
    
 ],

You can learn more about the Laravel Gate facade at Laravel Documentation. You can test it out as:

dd($user->can('permission-slug'));

 

 

Step 9: Add Dummy Data

We will create dummy data to check our user access.

Route::get('/roles', [PermissionController::class,'Permission']);

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()
    {   
    	$user_permission = Permission::where('slug','create-tasks')->first();
		$admin_permission = Permission::where('slug', 'edit-users')->first();

		//RoleTableSeeder.php
		$user_role = new Role();
		$user_role->slug = 'user';
		$user_role->name = 'User_Name';
		$user_role->save();
		$user_role->permissions()->attach($user_permission);

		$admin_role = new Role();
		$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 = new Permission();
		$createTasks->slug = 'create-tasks';
		$createTasks->name = 'Create Tasks';
		$createTasks->save();
		$createTasks->roles()->attach($user_role);

		$editUsers = new Permission();
		$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 = new User();
		$user->name = 'Test_User';
		$user->email = 'test_user@gmail.com';
		$user->password = bcrypt('1234567');
		$user->save();
		$user->roles()->attach($user_role);
		$user->permissions()->attach($user_perm);

		$admin = new User();
		$admin->name = 'Test_Admin';
		$admin->email = 'test_admin@gmail.com';
		$admin->password = bcrypt('admin1234');
		$admin->save();
		$admin->roles()->attach($admin_role);
		$admin->permissions()->attach($admin_perm);
		
		return redirect()->back();
    }
}

Now, Go to this URL. Then you will see some dummy data in the following tables.

$user = $request->user();
dd($user->hasRole('user')); //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

 

 

In our blade files, we can use it like :

@role('user')

 This is user role

@endrole

@role('admin')

 This is admin role

@endrole

This means only those users can see whose role is the user. Now you can use as many roles as you want.

 

Step 10: Setup the Middleware

In this step, we are creating middleware using the below command.

php artisan make:middleware RoleMiddleware

Add the middleware into your kernel.php file & set up the handle method.

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 RoleMiddleware in the Kernel.php file.

 

 

App\Http\Kernel.php

protected $routeMiddleware = [
    .
    .
    'role' => \App\Http\Middleware\RoleMiddleware::class,
];

Right now in our routes, you can do something like this :

Route::group(['middleware' => 'role:user'], function() {

   Route::get('/user', function() {

      return 'Welcome...!!';
      
   });

});

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')) {
        ...
    }
}

public function destroy(Request $request, $id)
{   
    if ($request->user()->can('delete-tasks')) {
      ...
    }

}

 


You might also like :

RECOMMENDED POSTS

FEATURE POSTS