Laravel 10 Gate And Policy Tutorial With Examples

https://www.laravelia.com/storage/logo.png

Gate and policy are the most important topics in Laravel. Like roles and permissions, we can also handle user access control using the gate and policy in the Laravel application. In Laravel, gates are simply closures that determine if a user is authorized to perform a given action. Policies are classes that organize also authorization logic around a particular model or resource.

In this tutorial, we will look up the gate as well as policy with perfect examples. I will use the latest Laravel 10 application to create this laravel gates and policies example. I will create a roles table and will create different types of roles and finally show you how to use the gate to control user access from that roles table.

laravel-10-gate-and-policy-tutorial-with-example

First of all, let’s see the example of the Laravel Gates tutorial:

Step 1: Download Laravel

First of all, we need a complete fresh Laravel 10 application. So download it by this command:

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

 

Step 2: Create Migration 

Run the following command to create a roles table:

php artisan make:migration add_role_column_to_users_table

 

Now open this migration file and update with the below code.

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->id();
            $table->enum('role',  ['admin', 'staff'])->default('staff');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('roles');
    }
};

 

Step 3: Connect Database

Now connect the database, cause we need migration for this Laravel roles and permissions example:

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=password

 

Now run migrate to add this table.

php artisan migrate

 

Read also: Laravel 10 Roles And Permissions Without Package

 

Step 4:  Create Gates

Now time to create gates for our application. So update the below file as like below:

app/Providers/AuthServiceProvider.php

<?php

namespace App\Providers;

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

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array<class-string, class-string>
     */
    protected $policies = [
        //
    ];

    /**
     * Register any authentication / authorization services.
     */
    public function boot(): void
    {
        Gate::define('isAdmin', function ($user) {
            return $user->role == 'admin';
        });

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

 

Step 5:  Use Gates in Blade

Now our gate declaration is done. Now we will see how to see that gate in the Laravel blade file. See the example:

resources/views/welcome.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('isAdmin')
                        <div class="btn btn-success btn-lg">
                          You have Admin Access
                        </div>
                    @endcan

                    @can('isStaff')
                        <div class="btn btn-primary btn-lg">
                          You have Staff Access
                        </div>
                    @else
                        <div class="btn btn-info btn-lg">
                          Default access
                        </div>
                    @endcan
  
                </div>
            </div>
        </div>
    </div>
</div>
@endsection 

 

Now let’s see how to use Laravel Gate in the controller:

App\Http\Controllers\TutorialController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Gate;

class TutorialController extends Controller
{
    public function __invoke()
    {
        if (Gate::allows('isAdmin')) {
            dd('Admin allowed');
        }

        abort(403);
    }
}

 

We can also use the gate in our route file like below:

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;

Route::get('/home', [HomeController::class, 'index'])->middleware('can:isAdmin')->name('home');

 

Step 6: Create Policy

Now time to talk about Laravel policy. There is an artisan command make:policy to create policy in Laravel. So now create a policy using the below command:

php artisan make:policy PostPolicy

//Yu may specify a --model when executing the command:

php artisan make:policy PostPolicy --model=Post

 

Step 8: Register policies

In this step, we need to register our policy before using it. Register it in the following file:

app/Providers/AuthServiceProvider.php

<?php

namespace App\Providers;

use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

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

 

Once the policy has been registered, we may define methods for each action it authorizes in the PostPolicy class like below.

app/Policies/PostPolicy.php

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;

class PostPolicy
{
    /**
     * Determine whether the user can view any models.
     */
    public function viewAny(User $user): bool
    {
        //
    }

    /**
     * Determine whether the user can view the model.
     */
    public function view(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can create models.
     */
    public function create(User $user): bool
    {
        //
    }

    /**
     * Determine whether the user can update the model.
     */
    public function update(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can delete the model.
     */
    public function delete(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     */
    public function restore(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     */
    public function forceDelete(User $user, Post $post): bool
    {
        //
    }
}

 

The above look was the default policy. Now we will update it like this:

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;

class PostPolicy
{
    /**
     * Determine whether the user can view any models.
     */
    public function viewAny(User $user): bool
    {
        //
    }

    /**
     * Determine whether the user can view the model.
     */
    public function view(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can create models.
     */
    public function create(User $user): bool
    {
        //
    }

    /**
     * Determine whether the user can update the model.
     */
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }

    /**
     * Determine whether the user can delete the model.
     */
    public function delete(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     */
    public function restore(User $user, Post $post): bool
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     */
    public function forceDelete(User $user, Post $post): bool
    {
        //
    }
}

 

Now let’s see how to use this policy in our controller update method:

App\Http\Controllers\TutorialController.php

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Support\Facades\Gate;

class TutorialController extends Controller
{
    public function update(Post $post)
    {
        if (auth()->user()->can('update', $post)) {
            //user is authorized to perform this action
        }
        return view('welcome');
    }
}

 

Or you can authorize user like this:

App\Http\Controllers\TutorialController.php

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Support\Facades\Gate;

class TutorialController extends Controller
{
    public function update(Post $post)
    {
        $this->authorize('update', $post);
    }
}

 

We can also use policy in Laravel routes like below:

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TutorialController;

Route::get('post/{post}', TutorialController::class)->middleware('can:update,post');

 

Now in the final part, we will see how to use laravel policy in blade file:

@can('update', $post)
    
@elsecan('create', App\Models\Post::class)
    
@endcan

@cannot('update', $post)
    
@elsecannot('create', App\Models\Post::class)
    
@endcannot

 

Read also: Laravel 10 PayPal Payment And Dive Into Details

 

Conclusion

You know how to use laravel policy and laravel gates in laravel application. Hope this laravel gate policy tutorial will help you to handle user authorization.

Laravel News Links