Chapter 12 - Manage Role Permissions using Middleware

Hello Artisan's, welcome to the 12th chapter of being an Artisanary. In this chapter we'll see the Role permission using middleware. So if you already complete the previous chapters/sections, then you're good to go, if not my recommendation would be please complete the previous chapters. Because we'll use the same old repository that we use in chapter 4 and also need to create some CRUD that will not cover today, because already saw a CRUD in the last chapter. 

Note: Tested on Laravel 10.0

Table of Contents

  1. Create and Setup Middleware 
  2. Create and Setup Helper Function for Checking Permission 
  3. Output

Create and Setup Middleware

First of all, we'll create a middleware by firing the below command

php artisan make:middleware PermissionMiddleware

It'll create a middleware under app/Http/Middleware/PermissionMiddleware.php, put the below source code 

PermissionMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class PermissionMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        if (auth()->check())
        {
            $role = auth()->user()->role;
            $permissions = collect($role->permissions);

            if (".create" == substr($request->route()->getName(), -7)) {
                if ($permissions->contains(str_replace(".create", ".store", $request->route()->getName()))) {
                    return $next($request);
                } else {
                    abort(403);
                }
            }

            if (".update" == substr($request->route()->getName(), -7)) {
                if ($permissions->contains(str_replace(".update", ".edit", $request->route()->getName()))) {
                    return $next($request);
                } else {
                    abort(403);
                }
            } else {

                if ($permissions->contains($request->route()->getName())) {
                    return $next($request);
                } else {
                    abort(403);
                }
            }
        }
        abort(403);
    }
}

Let's see what we actually do here. First of all for permission we'll store all the route name roles table. And while creating an user we'll assign each user a role. Then when a user wants to visit in a specific route then we'll check if the “Auth” user has the permission for it or not. And based on that condition we'll redirect the user.

And if you see our Github repo, we actually perform two CRUD's, one for role where we'll define the permissions. Look at the below screenshots.

And while creating user we assign each user a unique role. See the below screenshot.

And thus we filter the permission on our PermissionMiddleware. And yes I don't want speak about the CRUD's, because we already perform a CRUD in our previous chapter.

Then we'll register on app/Http/Kernel.php under the $middlewareAliases, look at the below source code

Kernel.php
protected $middlewareAliases = [
        ......
        'permission' => \App\Http\Middleware\PermissionMiddleware::class,
    ];

Create and Setup Helper Function for Checking Permission

First of all we need a method where we can show the content based on the permission which can be used in both blade and controller.

That's why we need a Helper functions. For creating helper function, first we'll create a folder under app/Helpers/Helpers.php and in to the file we'll create function as like as below

Helpers.php
<?php

if (!function_exists('hasPermission')) {

    function hasPermission($key_word): bool
    {
        if (in_array($key_word, auth()->user()->role->permissions) || auth()->user()->role_id == 1) {
            return true;
        }
        return false;
    }
}

The we need to register it in composer.json under autoload object like below,

composer.json
{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "require": {
        "php": "^8.1",
        "guzzlehttp/guzzle": "^7.2",
        "intervention/image": "^2.7",
        "laravel/framework": "^10.0",
        "laravel/sanctum": "^3.2",
        "laravel/tinker": "^2.8"
    },
    "require-dev": {
        "fakerphp/faker": "^1.9.1",
        "laravel/breeze": "^1.20",
        "laravel/pint": "^1.0",
        "laravel/sail": "^1.18",
        "mockery/mockery": "^1.4.4",
        "nunomaduro/collision": "^7.0",
        "phpunit/phpunit": "^10.0",
        "spatie/laravel-ignition": "^2.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        },
        "files": [
            "app/Helpers/Helpers.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

After register, you've fire the below command in the terminal.

composer dump-autoload

And now we can use anywhere we want. Like we used in our sidebar.blade.php as below

resources/views/backend/layouts/sidebar.blade.php
@if(hasPermission('users.index'))
 <li class="nav-item">
  <a href="{{ route('users.index') }}"
   class="nav-link {{ request()->is('users*')  ? 'active' : '' }}">
   <i class="nav-icon fas fa-user"></i>
   <p> User</p>
  </a>
 </li>
@endif

Output

And finally, we're ready with our setup. It's time to check our output. Now go to http://artisanary.test/users, If everything goes well (hope so) we can see the below output.

 

But if we don't have the permission, you can see the below the screen

And yes notice one thing in everywhere in Middleware and Helper function, in both places we ignore or return true whose role_id is 1 because normally Super Admin has the role_id 1 and we don't want to check any permission for Super Admin. That's only for testing, you can remove it if you want.

So, it's time to say goodbye for today. We saw the Role Permission manage without using any package. And yes keep up to date with the Github repository. That's it for today. See you in my next chapter. Happy coding 🙂.