DEV Community

Cover image for Implementing Simple Role-Based Authorization in Laravel 8 using Gates
Zack Webster
Zack Webster

Posted on • Edited on

Implementing Simple Role-Based Authorization in Laravel 8 using Gates

Let's see how to set up a simple role-based authorization system in Laravel 8.
In this tutorial, I'll set up a single-role-based system but you can expand the same to a multi-role-based one. Similarly, I'll be pulling the roles and permissions from an array instead of a database. We will implement authorization using gates.
I plan to cover a more advanced version of the same in the future but I believe, understanding a concept is much easier when it is simplified and to the point. I'll recommend going through Laravel 8 authorization docs once before reading this article.

You can view all the source on my GitHub repo, which is slightly modified for demonstration.

About our Application

In order to explain, I'll be creating an application with 3 roles - admin, manager & customer. And our permissions will be based around products - creating, updating, viewing, deleting. While managers & admins have all permissions, customers should only be able to view.

Getting Started

Once you have installed and set up Laravel. We'll scaffold authentication using the PHP artisan ui bootstrap --auth command followed by npm install & npm run dev.
You can do so with any of the other authentication scaffoldings you are familiar with and adjust accordingly.

Adding Role to Migration

Open up the create_users_table_table migration file in database/migrations.
We modify the scaffolded schema and set up a role column that will store a string and will have 'customer' as the default value.

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('role')->default('customer');
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
Enter fullscreen mode Exit fullscreen mode

Setting up our Authentication Mechanism

Open AuthServiceProvider inside app/Providers. Let's add a permissions array to the class within.

public static $permissions = [
    'index-product' => ['manager', 'customer'],
    'show-product' => ['manager', 'customer'],
    'create-product' => ['manager'],
    'store-product' => ['manager'],
    'edit-product' => ['manager'],
    'update-product' => ['manager'],
    'destroy-product' => ['manager'],
];
Enter fullscreen mode Exit fullscreen mode

What's going on here? This is an array in the form of $action => $roles[].

Setting our Gates

We modify the boot() function with our logic.

public function boot()
{
    $this->registerPolicies();

        // Roles based authorization
    Gate::before(
        function ($user, $ability) {
            if ($user->role === 'admin') {
                return true;
            }
        }
    );

    foreach (self::$permissions as $action=> $roles) {
        Gate::define(
            $action,
            function (User $user) use ($roles) {
                if (in_array($user->role, $roles)) {
                    return true;
                }
            }
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, using Gates:before() we allow the admin access to all abilities by returning true if user role is admin.
Next, we loop through our permissions array and define a gate for each. Where in, we check if the role of the user is in the roles associated to the actions.

We have basically mapped our permissions array to gates.

Using our Authorization System

With everything all set, we can now use the system.

In our Controllers

By using the authorize() method.

$this->authorize('update-product');
Enter fullscreen mode Exit fullscreen mode

In our Models

By using the can() method.

$this->can('update-product');
Enter fullscreen mode Exit fullscreen mode

In our Views

By using the @can blade directive method.

@can('update-product')
    //
@endcan
Enter fullscreen mode Exit fullscreen mode

Via our Models

By using the can() method.

if ($user->can('update-product')) {
    //
}
Enter fullscreen mode Exit fullscreen mode

Via Middleware

By using can:action-name middleware.

Route::put('/product/{Product}', [PostController::class, 'update'])->middleware('can:update-post');
Enter fullscreen mode Exit fullscreen mode

That's All

This article should have given you a general idea of how you can create an authorization system. While this is basic, you can add to & improve the implementation to support the features you need.

Liked what you read? Support me here: https://www.buymeacoffee.com/zaxwebs

Top comments (6)

Collapse
 
mhsagor110090 profile image
Mehedi Hasan Sagor

good

Collapse
 
abeltiezazu profile image
Abel Tiezazu

and also whats the advantage you using Array

Collapse
 
zaxwebs profile image
Zack Webster

There are other methods that are far better than an array. But for the sake of keeping it simple for the tutorial, I used an array.

Collapse
 
abeltiezazu profile image
Abel Tiezazu

where i can found boot() function

Collapse
 
zaxwebs profile image
Zack Webster

"AuthServiceProvider inside app/Providers" :)

Collapse
 
tediscript profile image
tediscript

awesome!