laravel permissions Tutorial with Example

Today, We want to share with you laravel permissions.In this post we will show you Easy roles and permissions in Laravel 5|6|7, hear for laravel roles and permissions from scratch we will give you demo and example for implement.In this post, we will learn about User Authorization in Laravel 5|6|7 with Spatie Laravel-Permission with an example.

laravel permissions

There are the Following The simple About laravel 5.6 – user roles and permissions Full Information With Example and source code.

As I will cover this Post with live Working example to develop spatie/laravel-permission documentation, so the laravel 6 roles and permissions is used for this example is following below.

Laravel authorization and positions permission management

Scaffold app

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

Setup packages

composer.json

"require": {
        ...
        "spatie/laravel-permission": "^2.1",
        "laracasts/flash": "^3.0",
        "laravelcollective/html": "^5.3.0"
    },

config/app.php

'providers' => [
    ...
    Spatie\Permission\PermissionServiceProvider::class,        
    Laracasts\Flash\FlashServiceProvider::class,        
    Collective\Html\HtmlServiceProvider::class,
    ...
],

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

create tables for positions and permissions.

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

create Visitor, Position, Permission

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

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

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

add HasPositions trait provided by the package

use Spatie\Permission\Traits\HasPositions;

class Member extends Authenticatable
{
    use HasPositions;
    ...

database/seeds/DatabaseSeeder.php

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

                // create one member for each position
                $this->createMember($position);
            }

            $this->command->info('Positions ' . $input_positions . ' added successfully');

        } else {
            Position::firstOrCreate(['name' => 'Member']);
            $this->command->info('Added only default member position.');
        }

        // now lets seed some visitors for demo
        factory(\App\Visitor::class, 30)->create();
        $this->command->info('Some Visitors data seeded.');
        $this->command->warn('All done :)');
    }

    /**
     * Create a member with given position
     *
     * @param $position
     */
    private function createMember($position)
    {
        $member = factory(Member::class)->create();
        $member->assignPosition($position->name);

        if( $position->name == 'Admin' ) {
            $this->command->info('Here is your admin details to login:');
            $this->command->warn($member->email);
            $this->command->warn('Password is "secret"');
        }
    }

defaultPermissions in Permissions Model

public static function defaultPermissions()
{
    return [
        'view_members',
        'add_members',
        'edit_members',
        'delete_members',

        'view_positions',
        'add_positions',
        'edit_positions',
        'delete_positions',

        'view_visitors',
        'add_visitors',
        'edit_visitors',
        'delete_visitors',
    ];
}

Now run the seeder using php artisan db:seed

Also Read This ๐Ÿ‘‰   how to remove php extension from url in localhost?

MemberController.php

positions' => 'required|min:1'
    ]);

    // Get the member
    $member = Member::findOrFail($id);

    // Update member
    $member->fill($request->except('positions', 'permissions', 'password'));

    // check for password change
    if($request->get('password')) {
        $member->password = bcrypt($request->get('password'));
    }

    // Handle the member positions
    $this->syncPermissions($request, $member);

    $member->save();
    flash()->success('Member has been updated.');
    return redirect()->route('members.index');
}

public function destroy($id)
{
    if ( Auth::member()->id == $id ) {
        flash()->warning('Deletion of currently logged in member is not allowed :(')->important();
        return redirect()->back();
    }

    if( Member::findOrFail($id)->delete() ) {
        flash()->success('Member has been deleted');
    } else {
        flash()->success('Member not deleted');
    }

    return redirect()->back();
}

private function syncPermissions(Request $request, $member)
{
    // Get the submitted positions
    $positions = $request->get('positions', []);
    $permissions = $request->get('permissions', []);

    // Get the positions
    $positions = Position::find($positions);

    // check for current position changes
    if( ! $member->hasAllPositions( $positions ) ) {
        // reset all direct permissions for member
        $member->permissions()->sync([]);
    } else {
        // handle permissions
        $member->syncPermissions($permissions);
    }

    $member->syncPositions($positions);
    return $member;
}

perform CRUD operation with certain permissions for the specific use

Route::group( ['middleware' => ['auth']], function() {
    Route::resource('members', 'MemberController');
    Route::resource('positions', 'PositionController');
    Route::resource('visitors', 'VisitorController');
});

Authorization

...
@can('add_members')
    <a href="{{ route('members.create') }}" class="btn btn-primary btn-sm">
        <i class="glyphicon glyphicon-plus-sign"></i> Create
    </a>
@endcan
...

<table class="table table-bordered table-striped table-hover" id="data-table">
    <thead>
    <tr>
        ....
        <th>Created At</th>
        @can('edit_members', 'delete_members')
            <th class="text-center">Actions</th>
        @endcan
    </tr>
    </thead>
    <tbody>
    @foreach($result as $item)
        <tr>
            ...
            @can('edit_members')
            <td class="text-center">
                // action buttons
            </td>
            @endcan
        </tr>
    @endforeach
    </tbody>
</table>

Authorizable Trait

namespace App;

trait Authorizable
{
    private $abilities = [
        'index' => 'view',
        'edit' => 'edit',
        'show' => 'view',
        'update' => 'edit',
        'create' => 'add',
        'store' => 'add',
        'destroy' => 'delete'
    ];

    /**
     * Override of callAction to perform the authorization before
     *
     * @param $method
     * @param $parameters
     * @return mixed
     */
    public function callAction($method, $parameters)
    {
        if( $ability = $this->getAbility($method) ) {
            $this->authorize($ability);
        }

        return parent::callAction($method, $parameters);
    }

    public function getAbility($method)
    {
        $routeName = explode('.', \Request::route()->getName());
        $action = array_get($this->getAbilities(), $method);

        return $action ? $action . '_' . $routeName[0] : null;
    }

    private function getAbilities()
    {
        return $this->abilities;
    }

    public function setAbilities($abilities)
    {
        $this->abilities = $abilities;
    }
}

trait on MemberController.

use App\Authorizable;

class MemberController extends Controller
{
    use Authorizable;
    ...

AuthorizationException Exception Handler

app/Exceptions/Handler.php

public function render($request, Exception $exception)
{
    if ($exception instanceof AuthorizationException) {
        return $this->unauthorized($request, $exception);
    }

    return parent::render($request, $exception);
}

private function unauthorized($request, Exception $exception)
{
    if ($request->expectsJson()) {
        return response()->json(['error' => $exception->getMessage()], 403);
    }

    flash()->warning($exception->getMessage());
    return redirect()->route('home');
}

Position Management

create the positions management resource controller

class PositionController extends Controller
{
    use Authorizable;

    public function index()
    {
        $positions = Position::all();
        $permissions = Permission::all();

        return view('position.index', compact('positions', 'permissions'));
    }

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

        if( Position::create($request->only('name')) ) {
            flash('Position Added');
        }

        return redirect()->back();
    }

    public function update(Request $request, $id)
    {
        if($position = Position::findOrFail($id)) {
            // admin position has everything
            if($position->name === 'Admin') {
                $position->syncPermissions(Permission::all());
                return redirect()->route('positions.index');
            }

            $permissions = $request->get('permissions', []);
            $position->syncPermissions($permissions);
            flash( $position->name . ' permissions has been updated.');
        } else {
            flash()->error( 'Position with id '. $id .' note found.');
        }

        return redirect()->route('positions.index');
    }
}

create resources/views/position/index.blade.php

@extends('layouts.app')

@section('title', 'Positions & Permissions')

@section('content')
    <!-- Modal -->
    <div class="modal fade" id="positionModal" tabindex="-1" position="dialog" aria-labelledby="positionModalLabel">
        <div class="modal-dialog" position="document">
            {!! Form::open(['method' => 'post']) !!}

            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">ร—</span></button>
                    <h4 class="modal-title" id="positionModalLabel">Position</h4>
                </div>
                <div class="modal-body">
                    <!-- name Form Input -->
                    <div class="form-group @if ($errors->has('name')) has-error @endif">
                        {!! Form::label('name', 'Name') !!}
                        {!! Form::text('name', null, ['class' => 'form-control', 'placeholder' => 'Position Name']) !!}
                        @if ($errors->has('name')) <p class="help-block">{{ $errors->first('name') }}</p> @endif
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>

                    <!-- Submit Form Button -->
                    {!! Form::submit('Submit', ['class' => 'btn btn-primary']) !!}
                </div>
                {!! Form::close() !!}
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-5">
            <h3>Positions</h3>
        </div>
        <div class="col-md-7 page-action text-right">
            @can('add_positions')
                <a href="#" class="btn btn-sm btn-success pull-right" data-toggle="modal" data-target="#positionModal"> <i class="glyphicon glyphicon-plus"></i> New</a>
            @endcan
        </div>
    </div>


    @forelse ($positions as $position)
        {!! Form::model($position, ['method' => 'PUT', 'route' => ['positions.update',  $position->id ], 'class' => 'm-b']) !!}

        @if($position->name === 'Admin')
            @include('shared._permissions', [
                          'title' => $position->name .' Permissions',
                          'options' => ['disabled'] ])
        @else
            @include('shared._permissions', [
                          'title' => $position->name .' Permissions',
                          'model' => $position ])
            @can('edit_positions')
                {!! Form::submit('Save', ['class' => 'btn btn-primary']) !!}
            @endcan
        @endif

        {!! Form::close() !!}

    @empty
        <p>No Positions defined, please run <code>php artisan db:seed</code> to seed some dummy data.</p>
    @endforelse
@endsection

resources/views/shared/_permissions.blade.php

<div class="panel panel-default">
    <div class="panel-heading" position="tab" id="{{ isset($title) ? str_slug($title) :  'permissionHeading' }}">
        <h4 class="panel-title">
            <a position="button" data-toggle="collapse" data-parent="#accordion" href="#dd-{{ isset($title) ? str_slug($title) :  'permissionHeading' }}" aria-expanded="{{ $closed or 'true' }}" aria-controls="dd-{{ isset($title) ? str_slug($title) :  'permissionHeading' }}">
                {{ $title or 'Override Permissions' }} {!! isset($member) ? '<span class="text-danger">(' . $member->getDirectPermissions()->count() . ')</span>' : '' !!}
            </a>
        </h4>
    </div>
    <div id="dd-{{ isset($title) ? str_slug($title) :  'permissionHeading' }}" class="panel-collapse collapse {{ $closed or 'in' }}" position="tabpanel" aria-labelledby="dd-{{ isset($title) ? str_slug($title) :  'permissionHeading' }}">
        <div class="panel-body">
            <div class="row">
                @foreach($permissions as $perm)
                    <?php
                        $per_found = null;

                        if( isset($position) ) {
                            $per_found = $position->hasPermissionTo($perm->name);
                        }

                        if( isset($member)) {
                            $per_found = $member->hasDirectPermission($perm->name);
                        }
                    ?>

                    <div class="col-md-3">
                        <div class="checkbox">
                            <label class="{{ str_contains($perm->name, 'delete') ? 'text-danger' : '' }}">
                                {!! Form::checkbox("permissions[]", $perm->name, $per_found, isset($options) ? $options : []) !!} {{ $perm->name }}
                            </label>
                        </div>
                    </div>
                @endforeach
            </div>
        </div>
    </div>
</div>

Permissions Management

command by running php artisan make:command AuthPermissionCommand

Also Read This ๐Ÿ‘‰   ErrorException in Builder.php[solution]

class AuthPermissionCommand extends Command
{
    protected $signature = 'auth:permission {name} {--R|remove}';
    ...

    public function handle()
    {
        $permissions = $this->generatePermissions();

        if( $is_remove = $this->option('remove') ) {
            if( Permission::where('name', 'LIKE', '%'. $this->getNameArgument())->delete() ) {
                $this->warn('Permissions ' . implode(', ', $permissions) . ' deleted.');
            }  else {
                $this->warn('No permissions for ' . $this->getNameArgument() .' found!');
            }

        } else {
            foreach ($permissions as $permission) {
                Permission::firstOrCreate(['name' => $permission ]);
            }

            $this->info('Permissions ' . implode(', ', $permissions) . ' created.');
        }

        if( $position = Position::where('name', 'Admin')->first() ) {
            $position->syncPermissions(Permission::all());
            $this->info('Admin permissions');
        }
    }

    private function generatePermissions()
    {
        $abilities = ['view', 'add', 'edit', 'delete'];
        $name = $this->getNameArgument();

        return array_map(function($val) use ($name) {
            return $val . '_'. $name;
        }, $abilities);
    }
    
    private function getNameArgument()
    {
        return strtolower(str_plural($this->argument('name')));
    }
}

Free Live Chat for Any Issue

app/Console/Kernel.php

App\Console\Commands\AuthPermissionCommand;

class Kernel extends ConsoleKernel
{
    protected $commands = [
        AuthPermissionCommand::class
    ];
    ...

The auth:permission command is ready, now you can run it to add/remove permissions.If you added some permissions manually in the Database, donโ€™t forget to run/execute php artisan cache:forget spatie.permission.cache, otherwise new permissions wont work.

Also Read This ๐Ÿ‘‰   Google Style Text Avatar using PHP Example
Web Programming Tutorials Example with Demo

Read :

Summary

You can also read about AngularJS, ASP.NET, VueJs, PHP.

I hope you get an idea about laravel 6 roles and permissions.
I would like to have feedback on my infinityknow.com blog.
Your valuable feedback, question, or comments about this article are always welcome.
If you enjoyed and liked this post, donโ€™t forget to share.