Implementing Simple Role-Based Authorization in Laravel 8 using Gates
Tags: laravel, tutorial, webdev
Published: 2021-01-05 23:00:56

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](https://github.com/zaxwebs/ex-l8-rbac), 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.
```php
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();
        });
    }
```

# Setting up our Authentication Mechanism
Open `AuthServiceProvider` inside `app/Providers`. Let's add a permissions array to the class within.
```php
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'],
];
```
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.
```php
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;
				}
			}
		);
	}
}
```
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.
```php
$this->authorize('update-product');
```

## In our Models
By using the `can()` method.
```php
$this->can('update-product');
```

## In our Views
By using the `@can` blade directive method.
```php
@can('update-product')
    //
@endcan
```

## Via our Models
By using the `can()` method.
```php
if ($user->can('update-product')) {
    //
}
```

## Via Middleware
By using `can:action-name` middleware.
```php
Route::put('/product/{Product}', [PostController::class, 'update'])->middleware('can:update-post');
```

#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