Spread the love

Roles and permission in laravel are used to provide roles based authentication and in this post we will learn simplest wat to use roles and permission in laravel. In our application we want features and modules on basis of roles or permissions so that we can restrict users to access the content according to their accessibility.

To accomplish the users based permission and roles we will use spatie/laravel-permission package. This packages covers all aspects for roles and permission like assigning permission directly to user, roles to user, multiple role, sync, blade directives etc.

In this post we will take a simple example in which we will create a tables, migration and seeder then assign the roles and permission. we will create 3 roles as follow

  1. Writer
  2. Admin
  3. Super Admin

Writer will be able to add and edit articles, Admin will be able to publish and un publish articles and last Super Admin will be able to perform all activities. For super admin we will create a gate so super admin will be able to access everything without assigning the permission.

This example will work in version of laravel 5, laravel 6, laravel 7, laravel 7 and laravel 9 but you need to change the version of spatie/laravel-permission package according to your laravel version.

Step 1: Create a laravel project

First step is to create the Laravel project using composer command or you can also read the How to install laravel 8 ? and Laravel artisan command to generate controllers, Model, Components and Migrations

composer create-project laravel/laravel rolespermission

Step 2: Configure database

Next step is to configure the database for our project, table and data. So open .env or if file not exist then rename .env.example file to .env file in root folder and change below details

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=rolespermission
DB_USERNAME=root
DB_PASSWORD=

Step 3: Configure Roles and Permissions

First of all add the the package as follow

 composer require spatie/laravel-permission

publish the migration and the config/permission.php config file with:

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

check more info here: Installation

Output:

 INFO  Publishing assets.  

  Copying file [vendor/spatie/laravel-permission/config/permission.php] to [config/permission.php]  DONE
  Copying file [vendor/spatie/laravel-permission/database/migrations/create_permission_tables.php.stub] to [database/migrations/2022_08_20_124256_create_permission_tables.php]  DONE

Clear the caches first

php artisan optimize:clear

Output:

   INFO  Clearing cached bootstrap files.  

  events ............................................................ 1ms DONE
  views ............................................................. 0ms DONE
  cache ............................................................. 1ms DONE
  route ............................................................. 0ms DONE
  config ............................................................ 0ms DONE
  compiled .......................................................... 0ms DONE

Run migrations

php artisan migrate

Output:

 INFO  Preparing database.  

  Creating migration table ......................................... 35ms DONE

   INFO  Running migrations.  

  2014_10_12_000000_create_users_table ............................. 49ms DONE
  2014_10_12_100000_create_password_resets_table ................... 46ms DONE
  2019_08_19_000000_create_failed_jobs_table ....................... 49ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ............ 73ms DONE
  2022_08_20_124256_create_permission_tables ...................... 515ms DONE

Create Seeders for Roles, Permissions and Users

Here we will create three users writer, admin and superadmin with roles and permission.

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;

class RolesPermissionSeeder extends Seeder
{
    /**
     * Create the initial roles and permissions.
     *
     * @return void
     */
    public function run()
    {
        // Reset cached roles and permissions
        app()[PermissionRegistrar::class]->forgetCachedPermissions();

        // create permissions
        Permission::create(['name' => 'articles.view']);
        Permission::create(['name' => 'articles.edit']);
        Permission::create(['name' => 'articles.delete']);
        Permission::create(['name' => 'articles.publish']);
        Permission::create(['name' => 'articles.unpublish']);

        // create roles and assign existing permissions
        $role1 = Role::create(['name' => 'writer']);
        $role1->givePermissionTo('articles.view');
        $role1->givePermissionTo('articles.edit');
        $role1->givePermissionTo('articles.delete');

        $role2 = Role::create(['name' => 'admin']);
        $role2->givePermissionTo('articles.view');
        $role2->givePermissionTo('articles.publish');
        $role2->givePermissionTo('articles.unpublish');

        $role3 = Role::create(['name' => 'SuperAdmin']);
        // gets all permissions via Gate::before rule; see AuthServiceProvider

        // create demo users
        $user = \App\Models\User::factory()->create([
            'name' => 'Example User Writer',
            'email' => 'test@example.com',
        ]);
        $user->assignRole($role1);

        $user = \App\Models\User::factory()->create([
            'name' => 'Example Admin User',
            'email' => 'admin@example.com',
        ]);
        $user->assignRole($role2);

        $user = \App\Models\User::factory()->create([
            'name' => 'Example Super-Admin User',
            'email' => 'superadmin@example.com',
        ]);
        $user->assignRole($role3);
    }
}

As you can see we have created five permissions articles.view, articles.edit, articles.delete, articles.publish and articles.unpublish.

Then we have assigned articles.view, articles.edit, articles.delete to writer role. articles.publish and articles.unpublish to Admin role and then then we assigned all roles to users.

Now run seeders as follow

php artisan db:seed --class=RolesPermissionSeeder

As we know superadmin can access everything so let’s create a gate so super admin role can access everything in the system as follow

<?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 = [
        // 'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        // Implicitly grant "SuperAdmin" role all permission checks using can()
       Gate::before(function ($user, $ability) {
        if ($user->hasRole('SuperAdmin')) {
            return true;
        }
       });

       
    }
}

Step 4 : Create a controller

Next, Create the a controller and add the necessary imports and class. You can create by Laravel artisan or manually.

php artisan make:controller ArticleController 

Now, add the controller logic for roles and permission

    <?php

    namespace App\Http\Controllers;

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

    class ArticleController extends Controller
    {
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
        }

        public function loginAs(Request $request, $userid)
        {

            if ($userid > 0) {
                \Auth::guard()->login(User::find($userid));
            } else {
                \Auth::guard()->logout();
            }
            return redirect("show-articles");
        }


        public function show()
        {
            $isLoggedin = false;
            $user       = null;
            $articles   = null;
            if (\Auth::guard()->check()) {
                $isLoggedin = true;
                $user       = \Auth::guard()->user();
                // dd($user);

                $articles   = Article::paginate(10);
            }

            return view('articles', [
                "isLoggedin" => $isLoggedin,
                "user" => $user,
                "articles" => $articles
            ]);
        }



        public function edit(Request $request, $userid)
        {

            if ($request->user()->can("articles.edit")) {
                return "success";
            } else {
                return "Do not have permissions";
            }
        }

        public function delete(Request $request, $userid)
        {

            if ($request->user()->can("articles.delete")) {
                return "success";
            } else {
                return "Do not have permissions";
            }
        }
    }

Step 5 : Create the views

Here in this step we will create a view as follow

  1. resources/views/rolepermission/articles.blade.php – To list all articles

So here is the code for resources/views/rolepermission/articles.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Simplest Laravel User Roles and Permission - Readerstacks </title>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />

</head>

<body class="antialiased">
    <div class="container">
        <!-- main app container -->
        <div class="readersack">
            <div class="container">
                <div class="row">
                    <div class="col-md-12 ">
                        <h3>Simplest Laravel User Roles and Permission - Readerstacks</h3>

                        <div class="login-status">
                            @if($isLoggedin)
                            <h2 style='color:blue'>Logged in as {{$user->email}}</h2>
                            @endif

                            <div>
                                <a href="{{url('login-user/3')}}">Login as SuperAdmin</a> |
                                <a href="{{url('login-user/2')}}">Login as Admin</a> |
                                <a href="{{url('login-user/1')}}">Login as Writer</a> |
                                <a href="{{url('login-user/0')}}">Logout</a>
                            </div>
                        </div>

                        @if($isLoggedin && $user->can("articles.view"))
                        <div id="pagination_data">
                            <table class="table table-striped table-dark table-bordered">
                                <tr>
                                    <th>Sr No.</th>
                                    <th>Title</th>
                                    <th>Body</th>

                                    <th>Date</th>
                                    <th>Action</th>
                                </tr>
                                @foreach($articles as $article)
                                <tr>
                                    <td>{{$article->id}}</td>

                                    <td>{{$article->title}}</td>
                                    <td>{{substr($article->body,0,50)}}</td>
                                    <td>{{$article->created_at}}</td>
                                    <td>
                                        @can(["articles.publish","articles.unpublish"])
                                        <a href="" class="btn btn-success">Publish</a>
                                        @endcan
                                        @can("articles.edit")
                                        <a href="{{route('articles.edit',$article->id) }}" class="btn btn-success">Edit</a>
                                        @endcan
                                        @can("articles.delete")
                                        <form action="{{ route('articles.destroy',$article->id) }}" method="Post">
                                            @csrf
                                            @method('DELETE')
                                            <button type="submit" class="btn btn-danger">Delete</button>
                                        </form>
                                        @endcan


                                    </td>
                                </tr>
                                @endforeach
                            </table>
                            <div id="pagination">
                                {{ $articles->links() }}
                            </div>
                        </div>
                        @else
                        <p style='color:red'>You do not have permission to View Articles</p>
                        @endif
                    </div>
                </div>
            </div>
        </div>
        <!-- credits -->
        <div class="text-center">
            <p>
                <a href="#" target="_top">Simplest Laravel User Roles and Permission
                </a>
            </p>
            <p>
                <a href="https://readerstacks.com" target="_top">readerstacks.com</a>
            </p>
        </div>
    </div>

</body>

</html>

@can – is a blade directive used to check the assigned permissions.

Step 6 : Create Route

Last and final step is to create the route for our roles and permission controller to serve the role based users permission

<?php

use Illuminate\Support\Facades\Route;
 
Route::get('/show-articles', "\App\Http\Controllers\ArticleController@show" );
Route::get('/login-user/{id}', "\App\Http\Controllers\ArticleController@loginAs" );
Route::get('/edit/{id}', "\App\Http\Controllers\ArticleController@edit" )->name("articles.edit");
Route::post('/delete/{id}', "\App\Http\Controllers\ArticleController@delete" )->name("articles.destroy");
 

Leave a Reply