Laravel 5.4 Users Authorization With Spatie Laravel-Permission

Today, Laravelcode share with you a very helfull tutorials related laravel role base permission system, we are share with you Laravel 5.4 Usesr Authorization With Spatie Laravel-Permission.

When you are craete any big lavel laravel application you must be needed set up user access control list (ACL) functionality for manage user role and permission for some perticuler right and athority. you manage all enty user managemant system base on role and permission which user can access which type functionality in your application. for example you ecreate one blog system and you want to give some perticuler permission to some perticuler user like some user only create blog post, some user only show blog post and they will be not to able to create blog post and not also delete any blog post. this is basic stuff for user access controll list(ACL) functionality.

Here, we are share with you how to create user access control list(ACL) functionality with laravel application using Spatie Laravel-Permission laravel package

We are apply access control list(ACL) on post article in this tutorials.

We are share here all code step by step so, please follow this step for crating laravel access control list(ACL) role permission step by step.

First we are starting look somethis it's method and how is work


givePermissionTo(): Allows us to give persmission to a user or role
revokePermissionTo(): Revoke permission from a user or role
hasPermissionTo(): Check if a user or role has a given permission
assignRole(): Assigns role to a user
removeRole(): Removes role from a user
hasRole(): Checks if a user has a role
hasAnyRole(Role::all()): Checks if a user has any of a given list of roles
hasAllRoles(Role::all()): Checks if a user has all of a given list of role

Step : 1 Install Required Packages

We are first need to install Spatie Laravel-Permission package. please run following comand for install this package in your laravel application.


composer require spatie/laravel-permission

Step : 2 Configure Packages

Now open your confige/app.php file and add package service provider into providers array like that


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

Now, we need to public or create this package's bydefault migration file by run following command :


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

Then after done this this proccess run migration by followign command :


php artisan migrate

Now, open your database and look into that their followign table created :

  • permissions : In this table we are store varius of permission
  • roles : In this table we are store user role
  • role_has_permission : This is one type of pivot table for relationship between permissions and roles table
  • model_has_roles : This also pivot table for relationship between roles and users table
  • model_has_permissions : This also pivot table for relationship between users and permissions table

Okay, now we are public configuration file by run following command :


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

Step : 3 Make changes in views/layout/app.blade.php file

Now, open your views/layout/app.blade.php file and here you make some changes like that simple put following all code in your file.


<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<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 id="token" name="csrf-token" value="{{ csrf_token() }}">
    <title>{{ config('app.name', 'Laravel') }}</title>
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    <script>
    window.csrf = "{{ csrf_token() }}";
    </script>
</head>
<body>
    <div id="">
        <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">
                        <li><a href="{{ url('/') }}">Home</a></li>
                        @if (!Auth::guest())
                            <li><a href="{{ route('posts.create') }}">New Article</a></li>
                        @endif
                    </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(Session::has('flash_message'))
            <div class="container">      
                <div class="alert alert-success"><em> {!! session('flash_message') !!}</em>
                </div>
            </div>
        @endif 

        <div class="row">
            <div class="col-md-8 col-md-offset-2">              
                @include ('errors.list') {{-- Including error file --}}
            </div>
        </div>

        @yield('content')

    </div>
    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
</body>
</html>

Step : 4 Create Routes

After changes in app.blade.php file then create following route in your web.php file.


// Laravel welcome route.
Route::get('/', function () {
    return view('welcome');
});

// Laravel auth route.
Auth::routes();

Route::get('/', 'PostController@index')->name('home');

// Users resource route.
Route::resource('users', 'UserController');

// Roles resource route.
Route::resource('roles', 'RoleController');

// Permissions resource route.
Route::resource('permissions', 'PermissionController');

// Post resource route.
Route::resource('posts', 'PostController');
	
Step : 5 Create Post Migration

Now, we are craete post migration using this command :


php artisan make:migration crate_post_tbl
	

Then open created post migration file from this path database/migrations and put inti it followign code.


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

class CreatePostTbl extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('post', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('description');
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::drop("post");
    }
}
	
Step : 6 Create Post Model

Now, create one post model in this path app/Post.php file and put following code into it.


namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
	public $table = 'post';

   	public $fillable = ['title','description'];
}
	
Step : 7 Create Post Controller

After post model created then we need to create controller in this path app/Http/Controllers/PostController.php file and put following code.


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;
use Auth;
use Session;

class PostController extends Controller {

    public function __construct() 
    {
        $this->middleware(['auth', 'clearance'])->except('index', 'show');
    }

    public function index() 
    {
        $posts = Post::orderby('id', 'desc')->paginate(5);
        return view('posts.index', compact('posts'));
    }
    
    public function create() 
    {
        return view('posts.create');
    }
    
    public function store(Request $request) 
    { 
        //Validation
        $this->validate($request, [
            'title'=>'required|max:100',
            'description' =>'required',
            ]);

        $title = $request['title'];
        $body = $request['description'];

        $post = Post::create($request->only('title', 'description'));

        //Display a successful message upon save
        return redirect()->route('posts.index')
            ->with('flash_message', 'Post,
             '. $post->title.' created');
    }
    
    public function show($id) 
    {
        $post = Post::findOrFail($id);
        return view ('posts.show', compact('post'));
    }
    
    public function edit($id) 
    {
        $post = Post::findOrFail($id);
        return view('posts.edit', compact('post'));
    }
    
    public function update(Request $request, $id) 
    {
        $this->validate($request, [
            'title'=>'required|max:100',
            'description'=>'required',
        ]);

        $post = Post::findOrFail($id);
        $post->title = $request->input('title');
        $post->body = $request->input('description');
        $post->save();

        return redirect()->route('posts.show', 
            $post->id)->with('flash_message', 
            'Post, '. $post->title.' updated');
    }
    
    public function destroy($id) 
    {
        $post = Post::findOrFail($id);
        $post->delete();

        return redirect()->route('posts.index')
            ->with('flash_message',
             'Post successfully deleted');
    }
}
	
Step : 8 Create View Files

We are user four view file in our PostController.php file. so, we must be create all view/blade files. we are created following blade file for Post Module.


1) \resources\views\posts\index.blade.php
2) \resources\views\posts\create.blade.php
3) \resources\views\posts\show.blade.php
4) \resources\views\posts\edit.blade.php

Our index.blade.php look like.


@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</h3></div>
                <div class="panel-heading">
                    Page {{ $posts->currentPage() }} of {{ $posts->lastPage() }}
                </div>
                @foreach ($posts as $post)
                    <div class="panel-body">
                        <li style="list-style-type:disc">
                            <a href="{{ route('posts.show', $post->id ) }}"><b>{{ $post->title }}</b><br>
                                <p class="teaser">
                                   {{  str_limit($post->description, 100) }}
                                </p>
                            </a>
                        </li>
                    </div>
                @endforeach
            </div>
            <div class="text-center">
                {!! $posts->links() !!}
            </div>
        </div>
    </div>
</div>
@endsection
	

Our create.blade.php look like.


@extends('layouts.app')

@section('title', '| Create New Post')

@section('content')
<div class="row">
    <div class="col-md-8 col-md-offset-2">
    <h1>Create New Post</h1>
    <hr>
    {{ Form::open(array('route' => 'posts.store')) }}
    <div class="form-group">
        {{ Form::label('title', 'Title') }}
        {{ Form::text('title', null, array('class' => 'form-control')) }}
        <br>
        {{ Form::label('body', 'Post Body') }}
        {{ Form::textarea('body', null, array('class' => 'form-control')) }}
        <br>
        {{ Form::submit('Create Post', array('class' => 'btn btn-success btn-lg btn-block')) }}
        {{ Form::close() }}
    </div>
    </div>
</div>
@endsection
	

Our create.blade.php look like.


@extends('layouts.app')

@section('title', '| Create New Post')

@section('content')
<div class="row">
    <div class="col-md-8 col-md-offset-2">
    <h1>Create New Post</h1>
    <hr>
    {{ Form::open(array('route' => 'posts.store')) }}
    <div class="form-group">
        {{ Form::label('title', 'Title') }}
        {{ Form::text('title', null, array('class' => 'form-control')) }}
        <br>
        {{ Form::label('description', 'Post Description') }}
        {{ Form::textarea('description', null, array('class' => 'form-control')) }}
        <br>
        {{ Form::submit('Create Post', array('class' => 'btn btn-success btn-lg btn-block')) }}
        {{ Form::close() }}
    </div>
    </div>
</div>
@endsection
	

Our show.blade.php look like.


@extends('layouts.app')

@section('title', '| View Post')

@section('content')
<div class="container">
    <h1>{{ $post->title }}</h1>
    <hr>
    <p class="lead">{{ $post->description }} </p>
    <hr>
    {!! Form::open(['method' => 'DELETE', 'route' => ['posts.destroy', $post->id] ]) !!}
    <a href="{{ url()->previous() }}" class="btn btn-primary">Back</a>
    @can('Edit Post')
    <a href="{{ route('posts.edit', $post->id) }}" class="btn btn-info" role="button">Edit</a>
    @endcan
    @can('Delete Post')
    {!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
    @endcan
    {!! Form::close() !!}
</div>
@endsection
	

Our edit.blade.php look like.


@extends('layouts.app')

@section('title', '| Edit Post')

@section('content')
<div class="row">
    <div class="col-md-8 col-md-offset-2">
        <h1>Edit Post</h1>
        <hr>
        {{ Form::model($post, array('route' => array('posts.update', $post->id), 'method' => 'PUT')) }}
        <div class="form-group">
        {{ Form::label('title', 'Title') }}
        {{ Form::text('title', null, array('class' => 'form-control')) }}
        <br>
        {{ Form::label('description', 'Post Description') }}
        {{ Form::textarea('description', null, array('class' => 'form-control')) }}
        <br>
        {{ Form::submit('Save', array('class' => 'btn btn-primary')) }}
        {{ Form::close() }}
    </div>
    </div>
</div>
@endsection
	

Now, run your laraval application and once you check your post module work perfect? (Here we have not still create middleware so only working home page but you are login and try to create new post then it's show error it's not big problem just continue...) it's all working okay then move anothe left step

Step : 9 Create User Controller

Now, we are create user module's controller and all view files. we have already User.php model for user so, this is not needed for create once again. we need to some changes like that.

Just open app/User.php file and put following code into it.


namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use Notifiable;
    use HasRoles;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function setPasswordAttribute($password)
    {   
        $this->attributes['password'] = bcrypt($password);
    }
}


create app/Http/Controllers/UserController.php file and put into it following code.


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;
use Auth;

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Session;

class UserController extends Controller {

    public function __construct() 
    {
        $this->middleware(['auth', 'isAdmin']); //middleware 
    }
    
    public function index() 
    {
        $users = User::all(); 
        return view('users.index')->with('users', $users);
    }

    public function create() 
    {
        $roles = Role::get();
        return view('users.create', ['roles'=>$roles]);
    }

    public function store(Request $request) 
    {
        $this->validate($request, [
            'name'=>'required|max:120',
            'email'=>'required|email|unique:users',
            'password'=>'required|min:6|confirmed'
        ]);

        $user = User::create($request->only('email', 'name', 'password')); 

        $roles = $request['roles']; //Retrieving the roles field
        //Checking if a role was selected
        if (isset($roles)) {
            foreach ($roles as $role) {
                $role_r = Role::where('id', '=', $role)->firstOrFail();            
                $user->assignRole($role_r); //Assigning role to user
            }
        }        
        //Redirect to the users.index view and display message
        return redirect()->route('users.index')
            ->with('flash_message',
             'User successfully added.');
    }

    public function show($id) 
    {
        return redirect('users'); 
    }
    
    public function edit($id) 
    {
        $user = User::findOrFail($id);
        $roles = Role::get(); //Get all roles
        return view('users.edit', compact('user', 'roles')); //pass user and roles data to view
    }
    
    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->only(['name', 'email', 'password']); 
        $roles = $request['roles'];
        $user->fill($input)->save();

        if (isset($roles)) {        
            $user->roles()->sync($roles);          
        }        
        else {
            $user->roles()->detach();
        }
        return redirect()->route('users.index')
            ->with('flash_message',
             'User successfully edited.');
    }

    public function destroy($id) 
    {
        $user = User::findOrFail($id); 
        $user->delete();

        return redirect()->route('users.index')
            ->with('flash_message',
             'User successfully deleted.');
    }
}

After done created UserController.php file then create all following blade file.


1) \resources\views\users\index.blade.php
2) \resources\views\users\create.blade.php
3) \resources\views\users\edit.blade.php

Our inde.blade.php look like.


@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 Administration <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></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>Actions</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>{{-- Retrieve array of roles associated to a user and convert to string --}}
                    <td>
                    <a href="{{ route('users.edit', $user->id) }}" class="btn btn-info pull-left" style="margin-right: 3px;">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>
    <a href="{{ route('users.create') }}" class="btn btn-success">Add User</a>
</div>
@endsection	

Our create.blade.php look like.


@extends('layouts.app')

@section('title', '| Add User')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-user-plus'></i> Add User</h1>
    <hr>
    {{ Form::open(array('url' => 'users')) }}
    <div class="form-group">
        {{ Form::label('name', 'Name') }}
        {{ Form::text('name', '', array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::label('email', 'Email') }}
        {{ Form::email('email', '', array('class' => 'form-control')) }}
    </div>
    <div class='form-group'>
        @foreach ($roles as $role)
            {{ Form::checkbox('roles[]',  $role->id ) }}
            {{ Form::label($role->name, ucfirst($role->name)) }}
            <br>
        @endforeach
    </div>
    <div class="form-group">
        {{ Form::label('password', 'Password') }}
        <br>
        {{ Form::password('password', array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::label('password', 'Confirm Password') }}
        <br>
        {{ Form::password('password_confirmation', array('class' => 'form-control')) }}
    </div>
    {{ Form::submit('Add', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection	

Our edit.blade.php look like.


@extends('layouts.app')

@section('title', '| Edit User')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-user-plus'></i> Edit {{$user->name}}</h1>
    <hr>
    {{ Form::model($user, array('route' => array('users.update', $user->id), 'method' => 'PUT')) }}
    <div class="form-group">
        {{ Form::label('name', 'Name') }}
        {{ Form::text('name', null, array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::label('email', 'Email') }}
        {{ Form::email('email', null, array('class' => 'form-control')) }}
    </div>
    <h5><b>Give Role</b></h5>
    <div class='form-group'>
        @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">
        {{ Form::label('password', 'Password') }}
        <br>
        {{ Form::password('password', array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::label('password', 'Confirm Password') }}
        <br>
        {{ Form::password('password_confirmation', array('class' => 'form-control')) }}
    </div>
    {{ Form::submit('Add', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

Now, we are done our users module. then go nex step...

Step : 10 Create PermissionController Controller

Now, we are create our Permissions module. here we are create PermissionController and all views/blades file.

So, first create controller go this path and create app/Http/Controllers/PermissionController.php file and put following code into it.


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Auth;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Session;

class PermissionController extends Controller {

    public function __construct() 
    {
        $this->middleware(['auth', 'isAdmin']); //middleware
    }

    public function index() 
    {
        $permissions = Permission::all();
        return view('permissions.index')->with('permissions', $permissions);
    }
    
    public function create() 
    {
        $roles = Role::get();
        return view('permissions.create')->with('roles', $roles);
    }

    public function store(Request $request) 
    {
        $this->validate($request, [
            'name'=>'required|max:40',
        ]);

        $name = $request['name'];
        $permission = new Permission();
        $permission->name = $name;

        $roles = $request['roles'];

        $permission->save();

        if (!empty($request['roles'])) { //If one or more role
            foreach ($roles as $role) {
                $r = Role::where('id', '=', $role)->firstOrFail();
                $permission = Permission::where('name', '=', $name)->first();
                $r->givePermissionTo($permission);
            }
        }

        return redirect()->route('permissions.index')
            ->with('flash_message',
             'Permission'. $permission->name.' added!');
    }

    public function show($id) 
    {
        return redirect('permissions');
    }

    public function edit($id) 
    {
        $permission = Permission::findOrFail($id);
        return view('permissions.edit', compact('permission'));
    }

    public function update(Request $request, $id) 
    {
        $permission = Permission::findOrFail($id);
        $this->validate($request, [
            'name'=>'required|max:40',
        ]);
        $input = $request->all();
        $permission->fill($input)->save();

        return redirect()->route('permissions.index')
            ->with('flash_message',
             'Permission'. $permission->name.' updated!');
    }

    public function destroy($id) 
    {
        $permission = Permission::findOrFail($id);

        if ($permission->name == "Administer roles & permissions") {
            return redirect()->route('permissions.index')
            ->with('flash_message',
             'Cannot delete this Permission!');
        }

        $permission->delete();

        return redirect()->route('permissions.index')
            ->with('flash_message',
             'Permission deleted!');
    }
}

After done created controller then we are followign three view needed :


1) \resources\views\permissions\index.blade.php
2) \resources\views\permissions\create.blade.php
3) \resources\views\permissions\edit.blade.php

Our index.blade.php look like.


@extends('layouts.app')

@section('title', '| Permissions')

@section('content')
<div class="col-lg-10 col-lg-offset-1">
    <h1><i class="fa fa-key"></i>Available Permissions
    <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></h1>
    <div class="table-responsive">
        <table class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th>Permissions</th>
                    <th>Operation</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-info pull-left" style="margin-right: 3px;">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>
    <a href="{{ URL::to('permissions/create') }}" class="btn btn-success">Add Permission</a>
</div>
@endsection

Our create.blade.php look like.


@extends('layouts.app')

@section('title', '| Create Permission')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-key'></i> Add 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()) //If no roles exist yet
        <h4>Assign Permission to Roles</h4>
        @foreach ($roles as $role) 
            {{ Form::checkbox('roles[]',  $role->id ) }}
            {{ Form::label($role->name, ucfirst($role->name)) }}
            <br>
        @endforeach
    @endif
    <br>
    {{ Form::submit('Add', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

Our edit.blade.php look like.


@extends('layouts.app')

@section('title', '| Edit Permission')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-key'></i> Edit {{$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('Edit', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

After done Permissions module we are move our last module Roles

Step : 11 Create RoleController Controller

Now, we are create RoleController.php file and also their views file like that way.

Now create RoleController.php file in app/Http/Controllers folder and put into it following code.


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Auth;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Session;

class RoleController extends Controller {

    public function __construct() 
    {
        $this->middleware(['auth', 'isAdmin']);//middleware 
    }

    public function index() 
    {
        $roles = Role::all();
        return view('roles.index')->with('roles', $roles);
    }

    public function create() 
    {
        $permissions = Permission::all();
        return view('roles.create', ['permissions'=>$permissions]);
    }

    public function store(Request $request) 
    {
        $this->validate($request, [
            'name'=>'required|unique:roles|max:10',
            'permissions' =>'required',
            ]
        );

        $name = $request['name'];
        $role = new Role();
        $role->name = $name;

        $permissions = $request['permissions'];

        $role->save();
        
        foreach ($permissions as $permission) {
            $p = Permission::where('id', '=', $permission)->firstOrFail(); 
            $role = Role::where('name', '=', $name)->first(); 
            $role->givePermissionTo($p);
        }

        return redirect()->route('roles.index')
            ->with('flash_message',
             'Role'. $role->name.' added!'); 
    }

    public function show($id) 
    {
        return redirect('roles');
    }

    public function edit($id) 
    {
        $role = Role::findOrFail($id);
        $permissions = Permission::all();

        return view('roles.edit', compact('role', 'permissions'));
    }

    public function update(Request $request, $id) 
    {

        $role = Role::findOrFail($id);
        
        $this->validate($request, [
            'name'=>'required|max:10|unique:roles,name,'.$id,
            'permissions' =>'required',
        ]);

        $input = $request->except(['permissions']);
        $permissions = $request['permissions'];
        $role->fill($input)->save();

        $p_all = Permission::all();

        foreach ($p_all as $p) {
            $role->revokePermissionTo($p);
        }

        foreach ($permissions as $permission) {
            $p = Permission::where('id', '=', $permission)->firstOrFail();
            $role->givePermissionTo($p);
        }

        return redirect()->route('roles.index')
            ->with('flash_message',
             'Role'. $role->name.' updated!');
    }

    public function destroy($id)
    {
        $role = Role::findOrFail($id);
        $role->delete();

        return redirect()->route('roles.index')
            ->with('flash_message',
             'Role deleted!');
    }
}

After create RoleController then create following three views/blades file.


1) \resources\views\roles\index.blade.php
2) \resources\views\roles\create.blade.php
3) \resources\views\roles\edit.blade.php

Our index.blade.php look like.


@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
    <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></h1>
    <hr>
    <div class="table-responsive">
        <table class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th>Role</th>
                    <th>Permissions</th>
                    <th>Operation</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-info pull-left" style="margin-right: 3px;">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>
    <a href="{{ URL::to('roles/create') }}" class="btn btn-success">Add Role</a>
</div>
@endsection

Our create.blade.php look like.


@extends('layouts.app')

@section('title', '| Add Role')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-key'></i> Add 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('Add', array('class' => 'btn btn-primary')) }}
    {{ Form::close() }}
</div>
@endsection

Our edit.blade.php look like.


@extends('layouts.app')

@section('title', '| Edit Role')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><i class='fa fa-key'></i> Edit 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>
    <h5><b>Assign Permissions</b></h5>
    @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

Okay we are done all module now just remaining two middleware one is isAdmin and secont one is ClearanceMiddleware

Step : 12 Create isAdmin Middleware

Why we are create isAdmin middleware? this middleware is check user's To restrict access to the roles and permissions page,

Create AdminMiddleware.php file in this path app/Http/Middleware/ and put into followign code.


namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;
use App\User;

class AdminMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $user = User::all()->count();
        if (!($user == 1)) {
            if (!Auth::user()->hasPermissionTo('Administer roles & permissions')) {
                abort('401');
            }
        }

        return $next($request);
    }
}

After create AdminMiddleware.php then create second middleware.

Step : 13 Create clearance Middleware

Create ClearanceMiddleware.php file in this path app/Http/Middleware/ and put into followign code.


namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class ClearanceMiddleware {
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next) {        
        if (Auth::user()->hasPermissionTo('Administer roles & permissions')) {
            return $next($request);
        }

        if ($request->is('posts/create')) {
            if (!Auth::user()->hasPermissionTo('Create Post')) {
                abort('401');
            } else {
                return $next($request);
            }
        }

        if ($request->is('posts/*/edit')) {
            if (!Auth::user()->hasPermissionTo('Edit Post')) {
                abort('401');
            } else {
                return $next($request);
            }
        }

        if ($request->isMethod('Delete')) {
            if (!Auth::user()->hasPermissionTo('Delete Post')) {
                abort('401');
            } else {
                return $next($request);
            }
        }

        return $next($request);
    }
}

Step : 14 Add Middleware in kernel.php File

After done both of middleware then we must be needed add both of middleware into kernel.php file like that

Open /app/Http/kernel.php file and add following two line in bottom


protected $routeMiddleware = [
    ......
    ......
    'isAdmin' => \App\Http\Middleware\AdminMiddleware::class,
    'clearance' => \App\Http\Middleware\ClearanceMiddleware::class,
];

Step : 15 Create 401 page

In both of middleware when condition is false then they redirect to 401. so, we are create one static page for handle this 401 error

Create one 401.blade.php file in this path \resources\views\errors and put into follwowing simple html code.


@extends('layouts.app')

@section('content')
<div class='col-lg-4 col-lg-offset-4'>
    <h1><center>401<br>
    ACCESS DENIED</center></h1>
</div>
@endsection

Now, we are done all things so please add some dummy role and permisssion the open following url in your browser.


http://localhost:8000/permissions

Step : 15 Create Seeder for dummy data.

If you don't know how to added manualy records for permissions and role table then create one seed file, just open database/seeds/DatabaseSeeder.php file and put like that code for insert some dummy permissions records and also create admin user.


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

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // Ask for db migration refresh, default is no
        if ($this->command->confirm('Do you wish to refresh migration before seeding, it will clear all old data ?')) {
            // Call the php artisan migrate:refresh
            $this->command->call('migrate:refresh');
            $this->command->warn("Data cleared, starting from blank database.");
        }

        // Seed the default permissions
        Permission::firstOrCreate(['name' => 'Administer roles & permissions', 'guard_name' => 'isAdmin']);
        

        $this->command->info('Default Permissions added.');

        // Confirm roles needed
        if ($this->command->confirm('Create Roles for user, default is admin and user? [y|N]', true)) {

            // Ask for roles from input
            $input_roles = $this->command->ask('Enter roles in comma separate format.', 'Admin,User');

            // Explode roles
            $roles_array = explode(',', $input_roles);

            // add roles
            foreach($roles_array as $role) {
                $role = Role::firstOrCreate(['name' => trim($role), 'guard_name' => 'isAdmin']);

                if( $role->name == 'Admin' ) {
                    // assign all permissions
                    $role->syncPermissions(Permission::all());
                    $this->command->info('Admin granted all the permissions');
                } else {
                    // for others by default only read access
                    $role->syncPermissions(Permission::where('name', 'LIKE', 'view_%')->get());
                }

                // create one user for each role
                $this->createUser($role);
            }

            $this->command->info('Roles ' . $input_roles . ' added successfully');

        } else {
            Role::firstOrCreate(['name' => 'User']);
            $this->command->info('Added only default user role.');
        }

        // now lets seed some posts for demo
        $this->command->info('Some Posts data seeded.');
        $this->command->warn('All done :)');
    }

    /**
     * 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('Here is your admin details to login:');
            $this->command->warn($user->email);
            $this->command->warn('Password is "secret"');
        }
    }
}

Now we are ready to run our example so run bellow command ro quick run:


php artisan serve

Now you can open bellow URL on your browser:


http://localhost:8000/permissions

If you face any problem then please write a comment or give some suggestions for improvement. Thanks...

 Prev post

Next post