How To Use Laravel Gates And Policies?

0
5804
Laravel Gates And Policies

Authentication is an important process in every application, but sometimes you need to authorize the user. For example, think of a user who is logged in / authenticated but you want to prevent some specific access to the content with authorization. We call it permissions in a simple way. Laravel provides gates and policies for authorization.

You can choose gates or policies or both according to your application. Keep in mind, Gates are used when requested actions are not connected to any modes or resource. On the other hand Policies should be used when requested actions are attached to modes or resources.

# Prerequisite

Before digging deeper into learning laravel gates and policies, please follow the following commands to install laravel and authentication. I’m using laravel 8 for this tutorial. FYI, the Laravel authentication process was changed from laravel version 6. It needs laravel/ui package.

composer create-project --prefer-dist laravel/laravel
composer require laravel/ui
php artisan ui vue --auth
npm install && npm run dev
php artisan serve

It will start development server at localhost:8000

Firstly, users table with role column required to check above gates. So, let’s create role column in users table with migration:

php artisan make:migration add_role_column_to_users_table

Next, open migration file and add role column.

/* database > migrations > *_add_role_column_to_users_table.php */

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddRoleColumnToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->enum('role', ['admin', 'user'])->default('user');
        });
    }
   
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }
}

Ater that, migrate database with following command.

php artisan migrate

Finally, create two manual entries into the users table with the following query to simplify the process. The password of both users is "password". You can use it for login users.

Credentials:
=================
admin@test.com
password

user@test.com
password
INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `role`) VALUES
(1, 'Admin', 'admin@test.com', NULL, '$2y$10$BRsGA1.aS40cP.3bLDh2S.2NfMGb9MRmkj9PMaIbsYQwAS76CdAmC', NULL, '2020-12-10 04:48:51', '2020-12-10 04:48:51', 'admin'),
(2, 'User', 'user@test.com', NULL, '$2y$10$ttQ0rSGy/2pswivz5LngLesaAzCs0c9faynZgxc4ZFUVDOU1tqCtm', NULL, '2020-12-10 04:48:51', '2020-12-10 04:48:51', 'user');

# Defining Gates

Gates provides simple functionality and requires two parameters where the first one is the name of the gate and another one is a closure function. After defining gates it will determine if the user is authorized or not for specific content or request. You can define gates in App > Providers > AuthServiceProvider.php file’s boot method. Let’s create two gates is_admin and is_user to determine roles wise access to the content in the application.

/* app > Providers > AuthServiceProvider.php */

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{    
	protected $policies = [
            
    ];

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

        Gate::define('is_admin', function($user){
            return $user->role == 'admin';
        });

        Gate::define('is_user', function($user){
            return $user->role == 'user';
        });
    }
}

# Using Gates In Blade

After defining gates, open resources > views > home.blade.php file and update code as below. You can use @can, @elsecan, @cannot, @canany similarly to @if condition for the defined gates.

/* resources > views > home.blade.php */

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Dashboard</div>

                    <div class="card-body">

                        @can('is_admin')
                            <div class="btn btn-success btn-lg">
                                Hello, Admin
                            </div>
                        @else
                            <div class="btn btn-info btn-lg">
                                Hello, User
                            </div>
                        @endcan

                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Login with different users and check if gates are working. These are the basic gate actions to check authorization for the users.

# Using Gates In Routes

To use defined gates to the routes you can do it too. Add as middleware in route two authorize user with specific gate action.

/* routes > web.php */

Route::get('/user/delete', 'App\Http\Controllers\UsersController@delete')->middleware('can:is_admin');
Route::get('/user/show', 'App\Http\Controllers\UsersController@show')->middleware('can:is_user');

# Using Gates In Controller

Of course, you can restrict content into the controllers to there are two main methods to check the authorization called allows and denies.

/* app > Http > Controllers > UsersController.php */

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class UsersController extends Controller
{
    public function delete()
    {
        if (!Gate::allows('is_admin')) {
            abort(403);
        }
    }

    public function show()
    {
        if (Gate::denies('is_user')) {
            abort(403);
        }
    }

}

# Using Policies

Policies are used for some complex authorization logic for specific eloquent models or resources. For example, if you have a todo application and you want to restrict all users to update or delete their own todos then you can do that with policies.

# Creating Policies

You can generate policies with make:policy artisan command. Laravel will create new policies in app > Policies directory.

php artisan make:policy TodoPolicy
/* Passing --model will create basic crud functions in policy class */
php artisan make:policy TodoPolicy --model=Todo

# Register Policies In ServiceProvider

After creating policies you need to register it into app > Providers > AuthServiceProvider.php. It will notify Laravel which policy to use for authorization requests for a specific eloquent model.

/* app > Providers > AuthServiceProvider.php  */

<?php

namespace App\Providers;

use App\Policies\TodoPolicy;
use App\Models\Todo;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Todo::class => TodoPolicy::class,
    ];

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

# Writing Policy Methods

After that, you can add methods into TodoPolicy‘s methods to each authorization request. For example, create an update method to restrict users to update their own todos. The update method will receive two model instances User and Post. Let assume there is an id column in the User model related to user_id into the Post model. Comparing both into the update method will return true or false to determine that request is authorized or not.

/* app > Policies > TodoPolicy.php */

<?php

namespace App\Policies;

use App\Models\Todo;
use App\Models\User;

class TodoPolicy
{
    public function update(User $user, Todo $todo)
    {
        return $user->id === $todo->user_id;
    }
}

# Using Policy In Controller

To use policy into the controllers, you can use can or you can use the authorize helper method.

/* app > Http > Controllers > TodoController.php */

<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\Todo;
use Illuminate\Http\Request;

class TodoController extends Controller
{
    /**
     *  To check
     */
    public function update(User $user, Todo $todo)
    {
        // To check user is authorized to update todos
        if ($user->can('update', $todo)) {

        }
        //You can also authorize a user using helper function as below.
        $this->authorize('update', $todo);
    }   
}

# Using Policy In Routes

Same as the Gates you can use Policies into the routes using middleware. Defining middleware into the routes will filter all authorization requests for the given policies.

Route::post('/todos/update', 'App\Http\Controllers\TodoController@update')->middleware('can:update,App\Models\Todo');

# Using Policy In Blade

You can use @can, @cannot directives same as Gates into the Policies too.

/* resources > views > todos.blade.php */

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Todos</div>

                    <div class="card-body">

                        @can('update', $todo)
                            <div class="btn btn-success btn-lg">
                                You can update todos
                            </div>
                        @else
                            <div class="btn btn-info btn-lg">
                                You can't update todos
                            </div>
                        @endcan

                        OR YOU CAN PASS ELOQUENT MODEL DIRECTLY

                        @can('update', App\Models\Todo::class)
                            <div class="btn btn-success btn-lg">
                                You can update todos
                            </div>
                        @else
                            <div class="btn btn-info btn-lg">
                                You can't update todos
                            </div>
                        @endcan

                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Thats it for that tutorial. I hope this will help you to learn laravel gates and policies for authorization. Please comment or share this tutorial. Thankyou!

Learn more about Laravel Framework

Previous articleMultiple Database Connections In Laravel
Next articleLaravel Localization – Multi Language Website
Welcome to the world of web development, where technology and creativity come together to bring ideas to life. My name is Keyur Gadher, and as a web development blogger, I am here to share my knowledge and experience with you. From front-end web development to back-end programming, I will provide you with valuable tips, tricks, and techniques to help you create beautiful and functional websites that are tailored to your specific needs. Whether you're a beginner or a seasoned pro, I am here to help you take your web development skills to the next level. Join me today and let's start coding!

LEAVE A REPLY

Please enter your comment!
Please enter your name here