Laravel User Role and Permissions using Spatie package

Laravel User Role and Permissions using Spatie package

Roles and permission for a web application is very important things to manage whole applications features. So here, in this article i will let you know to create laravel user role and permissions (ACL) using spatie package.

Here, in this article we will create roles and permissions for a blog where we can give access to the users to create, update and delete posts or aticles. An blog can have multiple users and can not give whole access of blog to all the users.

For assigning a role to user and different permission to that role, we will create html view or UI and only admin can change and assign the roles and manage permission for each roles.

So for implementing roles and permissions (ACL) we will use spatie/laravel-permission laravel package. Let’s start implemetation process in some very simple steps.

Step 1: Install Laravel Application

To install a fresh laravel application, we just need to run the following composer command in our terminal or command prompt.

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

Now give permission to storage and cache directory using the command below.

sudo chmod -R 777 /var/www/html/blog/storage
sudo chmod -R 777 /var/www/html/blog/bootstrap/cache

After that, create a database let’s say blog and put the database configuration details into environment file (.env) available on root directory of project.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=db_user
DB_PASSWORD=db_password

Step 2: Install spatie/laravel-permission package

In this second step we will install spatie laravel permission package. So for doing this we just need to run the command.

composer require spatie/laravel-permission

After running the above command you will have laravel-permission package downloaded in your laravel application. Now open config/app.php file and add provider as written below.

config/app.php

'providers' => [
    ...
    Spatie\Permission\PermissionServiceProvider::class,
];

Next, we will need to publish migration file by running the command below.

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

After publishing migration file, need to migrate these migrations to create actual table in the database.

php artisan migrate

After running above migrate command if you get error like below. It might be possible you have old version of mysql.

[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table users add unique users_email_unique(email))

[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

So for resolving this issue, you just need to increase the length of default string like in the code written below.

app\Providers\AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}

After updating default string length, we will need to run migration again to create required tables.

Step 3: Install Laravel Collective HTML Form builder

Now, we will install laravel collective HTML form builder to create html form in laravel. So open your terminal and run the following command.

composer require laravelcollective/html

Now, open config/app.php file and add provider and alias for this html and form class like below.

'providers' => [
    ...
    Collective\Html\HtmlServiceProvider::class,
];

'aliases' => [
      ...
     'Form' => Collective\Html\FormFacade::class,
     'Html' => Collective\Html\HtmlFacade::class,
], 

Step 4: Create Models

While installing fresh laravel a User model already be created. So will will create other models for roles, permissions and posts tables. So open your terminal and run the following commands.

// Create Role model and resource controller
php artisan make:model Role -c --resource

// Create Permission model and resource controller
php artisan make:model Permission -c --resource

// Create Post model with migration and resource controller
php artisan make:model Post -m -c --resource

After running the above commands three mdels would be created. When you open your Roles ad Permission model, you will see these models extends Model.

class Role extends Model { }

Now we will need to change like below.

// Permission Model
class Permission extends \Spatie\Permission\Models\Permission { }

// Role Model
class Role extends \Spatie\Permission\Models\Role { }

And the point to be noted here, we have given -m as a parameter in the Post model create command. It means it will also create a migration file for creating posts table. So open this migration file and add structure like below.

Schema::create('posts', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->text('body');
    $table->timestamps();
});

Now run migrate command again to create posts table.

After that, open User.php (User model) file and add HasRoles trait as mentioned below.

use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable {
    use HasRoles;
     ...
}

Now open Permisson model and add some default permissions like below.

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Permission extends \Spatie\Permission\Models\Permission
{
    public static function defaultPermissions()
    {
        return [           
            'viewPost',
            'addPost',
            'editPost',
            'deletePost',
        ];
    }
}

Step 5: Seed Tables

In this step, we will seed tables from some raw data for testing purposes only. So for that we will use database seeder. Open this seeder fila and update the code like below.

database/seeds/DatabaseSeeder.php

<?php
use Illuminate\Database\Seeder;
use App\Permission;
use App\Role;
use App\User;
use App\Post;
class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
  public function run()
    {
        // Ask for confirmation to refresh migration
        if ($this->command->confirm('Do you wish to refresh migration before seeding, Make sure it will clear all old data ?')) {
            $this->command->call('migrate:refresh');
            $this->command->warn("Data deleted, starting from fresh database.");
        }
        // Seed the default permissions
        $permissions = Permission::defaultPermissions();
        foreach ($permissions as $permission) {
            Permission::firstOrCreate(['name' => $permission]);
        }
        $this->command->info('Default Permissions added.');
        // Ask to confirm to assign admin or user role
        if ($this->command->confirm('Create Roles for user, default is admin and user? [y|N]', true)) {
            // Ask for roles from input
            $roles = $this->command->ask('Enter roles in comma separate format.', 'Admin,User');
            // Explode roles
            $rolesArray = explode(',', $roles);
            // add roles
            foreach($rolesArray as $role) {
                $role = Role::firstOrCreate(['name' => trim($role)]);
                if( $role->name == 'Admin' ) {
                    // assign all permissions to admin role
                    $role->permissions()->sync(Permission::all());
                    $this->command->info('Admin will have full rights');
                } else {
                    // for others, give access to view only
                    $role->permissions()->sync(Permission::where('name', 'LIKE', 'view_%')->get());
                }
                // create one user for each role
                $this->createUser($role);
            }
            $this->command->info('Roles ' . $roles . ' added successfully');
        } else {
            Role::firstOrCreate(['name' => 'User']);
            $this->command->info('By default, User role added.');
        }
      
    }
    /**
     * Create a user with given role
     *
     * @param $role
     */
    private function createUser($role)
    {
        $user = factory(User::class)->create();
        $user->assignRole($role->name);
        if( $role->name == 'Admin' ) {
            $this->command->info('Admin login details:');
            $this->command->warn('Username : '.$user->email);
            $this->command->warn('Password : "secret"');
        }
    }
    
}

Now run the seeder command as mentioned below to seed in the table.

php artisan db:seed

Now all the configurations hve been done. We can create roles and permission and assign roles to the users. So let’s create these things.

Step 6: Create Routes

We will create some routes which is neccessary for this feature. And all these routes would be available only for authenticated users. So open routes/web.php file and add the routes written below.

Route::group( ['middleware' => ['auth']], function() {
    Route::resource('users', 'UserController');
    Route::resource('roles', 'RoleController');
    Route::resource('posts', 'PostController');
  Route::resource('permissions','PermissionController');
});

Step 7: Create/Update Controllers

In this step, we will create or update controllers. Since we have alredy created controllers at the time of creating models. So we will just open those controller and update all the methods to get required functionalities.

UserController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use App\Role;
use App\Permission;
class UserController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }
    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $users = User::latest()->paginate();
        return view('users.index', compact('users'));
    }
    public function create()
    {
        $roles = Role::get();        
        return view('users.create', compact('roles'));
    }
    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:6|confirmed',
            'roles' => 'required'
        ]);
        $user = User::create($request->except('roles'));
        
        if($request->roles <> ''){
            $user->roles()->attach($request->roles);
        }
        return redirect()->route('users.index')->with('success','User has been created');            
        
    }
    public function edit($id) {
        $user = User::findOrFail($id);
        $roles = Role::get(); 
        return view('users.edit', compact('user', 'roles')); 
    }
    public function update(Request $request, $id) {
        $user = User::findOrFail($id);   
        $this->validate($request, [
            'name'=>'required|max:120',
            'email'=>'required|email|unique:users,email,'.$id,
            'password'=>'required|min:6|confirmed'
        ]);
        $input = $request->except('roles');
        $user->fill($input)->save();
        if ($request->roles <> '') {
            $user->roles()->sync($request->roles);        
        }        
        else {
            $user->roles()->detach(); 
        }
        return redirect()->route('users.index')->with('success',
             'User successfully updated.');
    }
    public function destroy($id) {
        $user = User::findOrFail($id); 
        $user->delete();
        return redirect()->route('users.index')->with('success',
             'User successfully deleted.');
    }
}

RoleController.php

<?php
namespace App\Http\Controllers;
use App\Role;
use App\Permission;
use Illuminate\Http\Request;
class RoleController extends Controller
{
   
    public function __construct()
    {
        $this->middleware('auth');
    }
    public function index()
    {
        $roles = Role::all();
        return view('roles.index',compact('roles'));
    }
    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $permissions = Permission::all();//Get all permissions
        return view('roles.create', compact('permissions'));
    }
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'name'=>'required|unique:roles|max:10',
            'permissions' =>'required',
            ]
        );
        $role = new Role();
        $role->name = $request->name;
        $role->save();
        if($request->permissions <> ''){
            $role->permissions()->attach($request->permissions);
        }
        return redirect()->route('roles.index')->with('success','Roles added successfully');
    }
   
     public function edit($id) {
        $role = Role::findOrFail($id);
        $permissions = Permission::all();
        return view('roles.edit', compact('role', 'permissions'));
    }
    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Role  $role
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request,$id)
    {
        $role = Role::findOrFail($id);//Get role with the given id
    //Validate name and permission fields
        $this->validate($request, [
            'name'=>'required|max:10|unique:roles,name,'.$id,
            'permissions' =>'required',
        ]);
        $input = $request->except(['permissions']);
        $role->fill($input)->save();
        if($request->permissions <> ''){
            $role->permissions()->sync($request->permissions);
        }
        return redirect()->route('roles.index')->with('success','Roles updated successfully');
    }
    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Role  $role
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $role = Role::findOrFail($id);
        $role->delete();
        return redirect()->route('roles.index')
            ->with('success',
             'Role deleted successfully!');
    }
}

PermissionController.php

<?php
namespace App\Http\Controllers;
use App\Permission;
use App\Role;
use Illuminate\Http\Request;
class PermissionController extends Controller
{
    
    public function __construct()
    {
        $this->middleware('auth');
    }
    public function index()
    {
        $permissions = Permission::all();
        return view('permissions.index',compact('permissions'));
    }
    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $roles = Role::get(); //Get all roles
        return view('permissions.create',compact('roles'));
    }
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'name'=>'required|max:40',
        ]);
        $permission = new Permission();
        $permission->name = $request->name;
        $permission->save();
        if ($request->roles <> '') { 
            foreach ($request->roles as $key=>$value) {
                $role = Role::find($value); 
                $role->permissions()->attach($permission);
            }
        }
        return redirect()->route('permissions.index')->with('success','Permission added successfully');
    }
   
    public function edit(Permission $permission)
    {
        return view('permissions.edit', compact('permission'));
    }
    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Permission  $permission
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Permission $permission)
    {
        $this->validate($request, [
            'name'=>'required',
        ]);
        $permission->name=$request->name;
        $permission->save();
        return redirect()->route('permissions.index')
            ->with('success',
             'Permission'. $permission->name.' updated!');
    }
    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Permission  $permission
     * @return \Illuminate\Http\Response
     */
    public function destroy(Permission $permission)
    {
        $permission->delete();
        return redirect()->route('permissions.index')
            ->with('success',
             'Permission deleted successfully!');
    }
}

PostController.php

<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
    public function index()
    {
        $posts = Post::latest()->paginate(10); 
        return view('posts.index', compact('posts'));
    }
}

Step 8: Create Views/ Blade Template

In the above step, we have create multiple controllers as a module like RoleController for roles module, permission controller for permission module, post controller for posts module, user controller for user module. Now we will create view or blade templates which have alredy mentioned in the controllers. So create files and put the code as written in the blow code in each files.

Master Layout ‘resources/views/layouts/app.blade.php’

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ config('app.name', 'Laravel') }}</title>
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <!-- Collapsed Hamburger -->
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
                        <span class="sr-only">Toggle Navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <!-- Branding Image -->
                    <a class="navbar-brand" href="{{ url('/') }}">
                        {{ config('app.name', 'Laravel') }}
                    </a>
                </div>
                <div class="collapse navbar-collapse" id="app-navbar-collapse">
                    <!-- Left Side Of Navbar -->
                    <ul class="nav navbar-nav">
                        &nbsp;
                    </ul>
                    <!-- Right Side Of Navbar -->
                    <ul class="nav navbar-nav navbar-right">
                        <!-- Authentication Links -->
                        @if (Auth::guest())
                            <li><a href="{{ route('login') }}">Login</a></li>
                            <li><a href="{{ route('register') }}">Register</a></li>
                        @else
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>
                                <ul class="dropdown-menu" role="menu">
                                    <li>
                                        <a href="{{ route('logout') }}"
                                            onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                            Logout
                                        </a>
                                        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                            {{ csrf_field() }}
                                        </form>
                                    </li>
                                </ul>
                            </li>
                        @endif
                    </ul>
                </div>
            </div>
        </nav>
        @if ($message = Session::get('success'))
            <div class="alert alert-success">
                <p>{{ $message }}</p>
            </div>
        @endif
        @yield('content')
    </div>
    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
</body>
</html>

resources\views\users\index.blade.php

{{-- \resources\views\users\index.blade.php --}}
@extends('layouts.app')
@section('title', '| Users')
@section('content')
<div class="col-lg-10 col-lg-offset-1">
    <h1><i class="fa fa-users"></i> User Management 
    <a href="{{ route('roles.index') }}" class="btn btn-default pull-right">Roles</a>
    <a href="{{ route('permissions.index') }}" class="btn btn-default pull-right">Permissions</a>
    <a href="{{ route('users.create') }}" class="btn btn-success">Add User</a>
    </h1>
    <hr>
    <div class="table-responsive">
        <table class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Date/Time Added</th>
                    <th>User Roles</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($users as $user)
                <tr>
                    <td>{{ $user->name }}</td>
                    <td>{{ $user->email }}</td>
                    <td>{{ $user->created_at->format('F d, Y h:ia') }}</td>
                    <td>{{ $user->roles()->pluck('name')->implode(' ') }}</td>
                    <td>
                    <a href="{{ route('users.edit', $user->id) }}" class="btn btn-warning">Edit</a>
                    {!! Form::open(['method' => 'DELETE', 'route' => ['users.destroy', $user->id] ]) !!}
                    {!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
                    {!! Form::close() !!}
                    </td>
                </tr>
                @endforeach
            </tbody>
        </table>
    </div>
</div>
@endsection

resources\views\users\create.blade.php

{{-- \resources\views\users\create.blade.php --}}
@extends('layouts.app')
@section('title', '| Create User')
@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-user-plus'></i> Create User</h1>
    <hr>
    {!! Form::open(array('url' => 'users')) !!}
    <div class="form-group @if ($errors->has('name')) has-error @endif">
        {!! Form::label('name', 'Name') !!}
        {!! Form::text('name', '', array('class' => 'form-control')) !!}
    </div>
    <div class="form-group @if ($errors->has('email')) has-error @endif">
        {!! Form::label('email', 'Email') !!}
        {!! Form::email('email', '', array('class' => 'form-control')) !!}
    </div>
    <div class="form-group @if ($errors->has('roles')) has-error @endif">
        @foreach ($roles as $role)
            {!! Form::checkbox('roles[]',  $role->id ) !!}
            {!! Form::label($role->name, ucfirst($role->name)) !!}<br>
        @endforeach
    </div>
    <div class="form-group @if ($errors->has('password')) has-error @endif">
        {!! Form::label('password', 'Password') !!}<br>
        {!! Form::password('password', array('class' => 'form-control')) !!}
    </div>
    <div class="form-group @if ($errors->has('password')) has-error @endif">
        {!! Form::label('password', 'Confirm Password') !!}<br>
        {!! Form::password('password_confirmation', array('class' => 'form-control')) !!}
    </div>
    {!! Form::submit('Register', array('class' => 'btn btn-primary')) !!}
    {!! Form::close() !!}
</div>
@endsection

resources\views\users\edit.blade.php

{{-- \resources\views\users\edit.blade.php --}}
@extends('layouts.app')
@section('title', '| Update User')
@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-user-plus'></i> Update {{$user->name}}</h1>
    <hr>
    {{ Form::model($user, array('route' => array('users.update', $user->id), 'method' => 'PUT')) }}
    <div class="form-group @if ($errors->has('name')) has-error @endif">
        {{ Form::label('name', 'Name') }}
        {{ Form::text('name', null, array('class' => 'form-control')) }}
    </div>
    <div class="form-group @if ($errors->has('email')) has-error @endif">
        {{ Form::label('email', 'Email') }}
        {{ Form::email('email', null, array('class' => 'form-control')) }}
    </div>
    <h5><b>Assign Role</b></h5>
    <div class="form-group @if ($errors->has('roles')) has-error @endif">
        @foreach ($roles as $role)
            {{ Form::checkbox('roles[]',  $role->id, $user->roles ) }}
            {{ Form::label($role->name, ucfirst($role->name)) }}<br>
        @endforeach
    </div>
    <div class="form-group @if ($errors->has('password')) has-error @endif">
        {{ Form::label('password', 'Password') }}<br>
        {{ Form::password('password', array('class' => 'form-control')) }}
    </div>
    <div class="form-group @if ($errors->has('password')) has-error @endif">
        {{ Form::label('password', 'Confirm Password') }}<br>
        {{ Form::password('password_confirmation', array('class' => 'form-control')) }}
    </div>
    {{ Form::submit('Update', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

resources\views\roles\index.blade.php

@extends('layouts.app')
@section('title', '| Roles')
@section('content')
<div class="col-lg-10 col-lg-offset-1">
    <h1><i class="fa fa-key"></i> Roles Management
    <a href="{{ route('users.index') }}" class="btn btn-default pull-right">Users</a>
    <a href="{{ route('permissions.index') }}" class="btn btn-default pull-right">Permissions</a>
    <a href="{{ URL::to('roles/create') }}" class="btn btn-success">Add Role</a>
    </h1>
    <hr>
    <div class="table-responsive">
        <table class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th>Role</th>
                    <th>Permissions</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($roles as $role)
                <tr>
                    <td>{{ $role->name }}</td>
                    <td>{{ str_replace(array('[',']','"'),'', $role->permissions()->pluck('name')) }}</td>
                    <td>
                    <a href="{{ URL::to('roles/'.$role->id.'/edit') }}" class="btn btn-warning pull-left">Edit</a>
                    {!! Form::open(['method' => 'DELETE', 'route' => ['roles.destroy', $role->id] ]) !!}
                    {!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
                    {!! Form::close() !!}
                    </td>
                </tr>
                @endforeach
            </tbody>
        </table>
    </div>
</div>
@endsection

resources\views\roles\create.blade.php

{{-- \resources\views\roles\create.blade.php --}}
@extends('layouts.app')
@section('title', '| Create Role')
@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-key'></i> Create Role</h1>
    <hr>
    {{ Form::open(array('url' => 'roles')) }}
    <div class="form-group">
        {{ Form::label('name', 'Name') }}
        {{ Form::text('name', null, array('class' => 'form-control')) }}
    </div>
    <h5><b>Assign Permissions</b></h5>
    <div class='form-group'>
        @foreach ($permissions as $permission)
            {{ Form::checkbox('permissions[]',  $permission->id ) }}
            {{ Form::label($permission->name, ucfirst($permission->name)) }}<br>
        @endforeach
    </div>
    {{ Form::submit('Save', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

resources\views\roles\edit.blade.php

@extends('layouts.app')
@section('title', '| Update Role')
@section('content')
<div class='col-md-4 col-md-offset-4'>
    <h1><i class='fa fa-key'></i> Update Role: {{$role->name}}</h1>
    <hr>
    {{ Form::model($role, array('route' => array('roles.update', $role->id), 'method' => 'PUT')) }}
    <div class="form-group">
        {{ Form::label('name', 'Role Name') }}
        {{ Form::text('name', null, array('class' => 'form-control')) }}
    </div>
    <h3>Assign Permissions</h3>
    @foreach ($permissions as $permission)
        {{Form::checkbox('permissions[]',  $permission->id, $role->permissions ) }}
        {{Form::label($permission->name, ucfirst($permission->name)) }}<br>
    @endforeach
    <br>
    {{ Form::submit('Edit', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}    
</div>
@endsection

resources\views\permissions\index.blade.php

{{-- \resources\views\permissions\index.blade.php --}}
@extends('layouts.app')
@section('title', '| Permissions')
@section('content')
<div class="col-md-10 col-md-offset-1">
    <h1><i class="fa fa-key"></i>Permissions Management
    <a href="{{ route('users.index') }}" class="btn btn-default pull-right">Users</a>
    <a href="{{ route('roles.index') }}" class="btn btn-default pull-right">Roles</a>
    <a href="{{ URL::to('permissions/create') }}" class="btn btn-success">Add Permission</a>
    </h1>
    <hr>
    <div class="table-responsive">
        <table class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th>Permissions</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($permissions as $permission)
                <tr>
                    <td>{{ $permission->name }}</td> 
                    <td>
                    <a href="{{ URL::to('permissions/'.$permission->id.'/edit') }}" class="btn btn-warning pull-left">Edit</a>
                    {!! Form::open(['method' => 'DELETE', 'route' => ['permissions.destroy', $permission->id] ]) !!}
                    {!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
                    {!! Form::close() !!}
                    </td>
                </tr>
                @endforeach
            </tbody>
        </table>
    </div>
</div>
@endsection

resources\views\permissions\create.blade.php

@extends('layouts.app')
@section('title', '| Create Permission')
@section('content')
<div class='col-md-4 col-md-offset-4'>
    <h1><i class='fa fa-key'></i> Create New Permission</h1>
    <br>
    {{ Form::open(array('url' => 'permissions')) }}
    <div class="form-group">
        {{ Form::label('name', 'Name') }}
        {{ Form::text('name', '', array('class' => 'form-control')) }}
    </div><br>
    @if(!$roles->isEmpty()) 
        <h3>Assign Permission to Roles</h3>
        @foreach ($roles as $role) 
            {{ Form::checkbox('roles[]',  $role->id ) }}
            {{ Form::label($role->name, ucfirst($role->name)) }}<br>
        @endforeach
    @endif
    <br>
    {{ Form::submit('Save', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

resources\views\permissions\edit.blade.php

@extends('layouts.app')
@section('title', '| Update Permission')
@section('content')
<div class='col-md-4 col-md-offset-4'>
    <h1><i class='fa fa-key'></i> Update {{$permission->name}}</h1>
    <br>
    {{ Form::model($permission, array('route' => array('permissions.update', $permission->id), 'method' => 'PUT')) }}
    <div class="form-group">
        {{ Form::label('name', 'Permission Name') }}
        {{ Form::text('name', null, array('class' => 'form-control')) }}
    </div>
    <br>
    {{ Form::submit('Update', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

resources\views\posts\index.blade.php

@extends('layouts.app')
@section('content')
<div class="container">
   <div class="row">
      <div class="col-md-10 col-md-offset-1">
         <div class="panel panel-default">
            <div class="panel-heading">
               <h3>Posts Management</h3>
            </div>
            <div class="panel-body">
               <div class="table-responsive">
                  <table class="table table-bordered table-striped">
                     <thead>
                        <tr>
                           <th>Title</th>
                           <th>Body</th>
                           <th>Action</th>
                        </tr>
                     </thead>
                     <tbody>
                        @foreach ($posts as $post)
                        <tr>
                           <td>{{ $post->title }}</td>
                           <td>{{ $post->body }}</td>
                           <td>
                              @can('editPost')
                              <a href="{{ route('posts.edit', $post->id) }}" class="btn btn-info pull-left">Edit</a>
                              @endcan
                              @can('deletePost')
                              {!! Form::open(['method' => 'DELETE', 'route' => ['posts.destroy', $post->id] ]) !!}
                              {!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
                              {!! Form::close() !!}
                              @endcan
                           </td>
                        </tr>
                        @endforeach
                     </tbody>
                  </table>
               </div>
            </div>
         </div>
         <div class="text-center">
            {!! $posts->render() !!}
         </div>
      </div>
   </div>
</div>
@endsection

Step 9: Setup Middleware

Now, in this step we will restrict users to the middleware. Only admin user will have permission to full access.

And all theese routes will be protected by a middileware. Middleware file will look like the below.

Permission Middleware

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class PermissionMiddleware {
    
    public function handle($request, Closure $next) {        
        if (Auth::user()->hasRole('Admin')) //If user has admin role
        {
            return $next($request);
        }
        if (Auth::user()->hasRole('User')) //If user has user role
        {
            if ($request->is('posts/create'))//If user is creating a post
            {
                if (!Auth::user()->hasPermissionTo('addPost'))
                {
                   abort('401');
                } 
                else {
                   return $next($request);
                }
            }
        }
        return $next($request);
    }
}

Now we will need to register this middleware in app’s kernel like below.

app/Http/kernel.php 

protected $routeMiddleware = [
     ....
     'has_permission' => \App\Http\Middleware\PermissionMiddleware::class,
];

here in the middleware we have handled error 401 which is unauthorized. So let’s create a view file for displaying error like below.

401.blade.php

{{-- \resources\views\errors\401.blade.php --}}
@extends('layouts.app')
@section('content')
    <div class='col-md-4 col-md-offset-4'>
        <h3><center>401<br>
        You do not have permission</center></h3>
    </div>
@endsection

Thus, we have registered middleware to prevent unauthorized access of the routes.

Step 10: Deploy application for development 

As, we have done all the steps for Laravel User Role and Permissions using Spatie package. Now for checking on the development machine or local machine we will need to run the command below.

php artisan serve

After running above command. You are able to view this application on the following url.

http://localhost:8000

You can also read a beautiful tutorial on docker setup with laravel,php, mysql, nginx by clicking on the link below.

Create docker setup for laravel application with nginx and mysql example