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

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

Also Read This 👉   jQuery Alternate Dynamic Table Rows Color

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 👉   how to select category and subcategory dropdown in php MySQL?

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')));
    }
}

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.

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.