Laravel comes with Authentication and Authorization out of the box, I have implemented many role and permissions based system in the past, using laravel, it’s peace of cake. In this post, we are going to implement a fully working and extensible roles and permissions on laravel 5. When we finish we will have a starter kit which we can use for our any future project which needs roles and permissions based access control (ACL).
Laravel Permissions
Although laravel comes with Policies to handle the authorization I wanted to have an option to just create permissions in the database which we can manage by a UI in the admin panel, pretty standard. we can implement our own role and permission from scratch but I am going to use spatie/laravel-permission package for this. This package was inspired by Jeffrey ways screencast and it’s very well maintained and very easy to use. It has everything we need and plays very well with Laravel Gate and Policies implementations.
Source Code Laravel 5.4
Source Code Laravel 5.7
Scaffold app
Let’s get started by creating a fresh laravel app by running laravel new rpl
or if you don’t have laravel command line tool, you can use composer to get it composer create-project --prefer-dist laravel/laravel rpl
. rpl is the name of app which is an abbreviation for Role Permissions Laravel.
Once the installation is done, make necessary changes in .env
so you can connect to a database.
Setup packages
We will use laravel authorization which comes bundled, let’s scaffold it using auth:make
command. It will create a fully functional login, register and password reset features. Now that’s done, let’s pull packages we will need in this app.
Edit your composer.json
to add below dependencies.
"require": {
...
"spatie/laravel-permission": "^2.1",
"laracasts/flash": "^3.0",
"laravelcollective/html": "^5.3.0"
},
Apart from permissions package, I have also grabbed flash to show notification alerts and laravelcollective html to create forms with the option to model bind them.
Now Add them in ServiceProvider and in aliases array, open 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,
]
Cool, now let’s start by publishing migration which comes from permissions package, which will create tables for roles and permissions.
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"
Great, now we need to create our Resource, I am going to create Post, Role, Permission models with resource controller. User model is already present so we will use it.
// Create Post model with migration and resource controller
php artisan make:model Post -m -c --resource
// 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
Spatie\Permission already have role and permissions model, we will just extend them in order to do any changes if needed in future.
// Permission Model
class Permission extends \Spatie\Permission\Models\Permission { }
// Role Model
class Role extends \Spatie\Permission\Models\Role { }
We need to add HasRoles trait provided by the package to give the user all the power of laravel permissions.
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
...
Now we have all the boilerplate out of the way, let’s create simple database seeder so we can build and test our app, you can read more about advance database seeding in this post, open database/seeds/DatabaseSeeder.php
and add this code.
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
$permissions = Permission::defaultPermissions();
foreach ($permissions as $perms) {
Permission::firstOrCreate(['name' => $perms]);
}
$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)]);
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
factory(\App\Post::class, 30)->create();
$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 add defaultPermissions
in Permissions Model which we have created.
public static function defaultPermissions()
{
return [
'view_users',
'add_users',
'edit_users',
'delete_users',
'view_roles',
'add_roles',
'edit_roles',
'delete_roles',
'view_posts',
'add_posts',
'edit_posts',
'delete_posts',
];
}
Post model factory contains only 2 fileds, title and body. You should setup the migration and factory. Now run the seeder using php artisan db:seed
it should give an admin user which you can use to login.
Now you can login with admin user but there is no access control in place, I will create the User Resource first.
Create the UserController and add below code.
public function index()
{
$result = User::latest()->paginate();
return view('user.index', compact('result'));
}
public function create()
{
$roles = Role::pluck('name', 'id');
return view('user.new', compact('roles'));
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'bail|required|min:2',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
'roles' => 'required|min:1'
]);
// hash password
$request->merge(['password' => bcrypt($request->get('password'))]);
// Create the user
if ( $user = User::create($request->except('roles', 'permissions')) ) {
$this->syncPermissions($request, $user);
flash('User has been created.');
} else {
flash()->error('Unable to create user.');
}
return redirect()->route('users.index');
}
public function edit($id)
{
$user = User::find($id);
$roles = Role::pluck('name', 'id');
$permissions = Permission::all('name', 'id');
return view('user.edit', compact('user', 'roles', 'permissions'));
}
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'bail|required|min:2',
'email' => 'required|email|unique:users,email,' . $id,
'roles' => 'required|min:1'
]);
// Get the user
$user = User::findOrFail($id);
// Update user
$user->fill($request->except('roles', 'permissions', 'password'));
// check for password change
if($request->get('password')) {
$user->password = bcrypt($request->get('password'));
}
// Handle the user roles
$this->syncPermissions($request, $user);
$user->save();
flash()->success('User has been updated.');
return redirect()->route('users.index');
}
public function destroy($id)
{
if ( Auth::user()->id == $id ) {
flash()->warning('Deletion of currently logged in user is not allowed :(')->important();
return redirect()->back();
}
if( User::findOrFail($id)->delete() ) {
flash()->success('User has been deleted');
} else {
flash()->success('User not deleted');
}
return redirect()->back();
}
private function syncPermissions(Request $request, $user)
{
// Get the submitted roles
$roles = $request->get('roles', []);
$permissions = $request->get('permissions', []);
// Get the roles
$roles = Role::find($roles);
// check for current role changes
if( ! $user->hasAllRoles( $roles ) ) {
// reset all direct permissions for user
$user->permissions()->sync([]);
} else {
// handle permissions
$user->syncPermissions($permissions);
}
$user->syncRoles($roles);
return $user;
}
Everything is commented and self-explanatory, it’s a simple controller to perform CRUD operation with user level permission override so you can give access to certain permissions for the specific user. Now register the route for all the resource controllers.
Route::group( ['middleware' => ['auth']], function() {
Route::resource('users', 'UserController');
Route::resource('roles', 'RoleController');
Route::resource('posts', 'PostController');
});
Go ahead and create the PostController by yourself, you can always access the source code if need help.
Authorization
This is the main part, authorization will be in 2 level, first is at the controller level and second in view level. In view, if you don’t have permission to add_users
then it doesn’t make sense to show Create button. this can be done using @can('add_users')
directive in blade template.
...
@can('add_users')
<a href="{{ route('users.create') }}" class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-plus-sign"></i> Create
</a>
@endcan
...
Similarly, if you don’t have access to edit_users
you should not see the edit button or delete button in the table.
<table class="table table-bordered table-striped table-hover" id="data-table">
<thead>
<tr>
....
<th>Created At</th>
@can('edit_users', 'delete_users')
<th class="text-center">Actions</th>
@endcan
</tr>
</thead>
<tbody>
@foreach($result as $item)
<tr>
...
@can('edit_users')
<td class="text-center">
// action buttons
</td>
@endcan
</tr>
@endforeach
</tbody>
</table>
Now that’s fine, but some malicious user can still directly visit the URL and he will be able to access the protected route. To prevent that we need protection on controller@method level.
Authorizable Trait
We can add $user->can()
check in every method to handle authorization but it will make it more difficult to maintain and since we will be using this in multiple resource controller it will be good to extract out this logic in a trait which will handle the authorization automatically, sounds good! let’s do it.
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;
}
}
In this trait we have to override the callAction method which gets called by the router to trigger respective method on the resource controller, that’s good place to check the permission, so we get the route name in users case it will be users.index, users.store, users.update etc.. we have mapped the abilities to our resource controller route naming conventions.
what happens is when a user visits route named users.index
, it gets translated into view_users
ability to check against in authorize($ability)
method by getAbility() method, when user visits edit page route users.edit it will be translated as edit_users
and so on. by extracting this logic in a Trait we will be able to apply authorization on any resource controller we wanted.
Add our trait on UserController.
use App\Authorizable;
class UserController extends Controller
{
use Authorizable;
...
That’s it, your controller is protected, the only user who has permissions to visit certain route can access it.
When user doesn’t have permission they get AuthorizationException
exception, which is not very friendly to end user, let’s handle this in global Handler so we can display a notification and send the user back to dashboard if the try to visit some route which they don’t suppose to access.
AuthorizationException Exception Handler
Open the app/Exceptions/Handler.php and add this in render method
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');
}
This will redirect back to home route with flash notification if user doesn’t have access to the action.
Role Management
Let’s create the roles management resource controller. which admin can use to create the new role and give or change permission to them.
class RoleController extends Controller
{
use Authorizable;
public function index()
{
$roles = Role::all();
$permissions = Permission::all();
return view('role.index', compact('roles', 'permissions'));
}
public function store(Request $request)
{
$this->validate($request, ['name' => 'required|unique:roles']);
if( Role::create($request->only('name')) ) {
flash('Role Added');
}
return redirect()->back();
}
public function update(Request $request, $id)
{
if($role = Role::findOrFail($id)) {
// admin role has everything
if($role->name === 'Admin') {
$role->syncPermissions(Permission::all());
return redirect()->route('roles.index');
}
$permissions = $request->get('permissions', []);
$role->syncPermissions($permissions);
flash( $role->name . ' permissions has been updated.');
} else {
flash()->error( 'Role with id '. $id .' note found.');
}
return redirect()->route('roles.index');
}
}
Now lets add the views for role, create resources/views/role/index.blade.php with below markup.
@extends('layouts.app')
@section('title', 'Roles & Permissions')
@section('content')
<!-- Modal -->
<div class="modal fade" id="roleModal" tabindex="-1" role="dialog" aria-labelledby="roleModalLabel">
<div class="modal-dialog" role="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="roleModalLabel">Role</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' => 'Role 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>Roles</h3>
</div>
<div class="col-md-7 page-action text-right">
@can('add_roles')
<a href="#" class="btn btn-sm btn-success pull-right" data-toggle="modal" data-target="#roleModal"> <i class="glyphicon glyphicon-plus"></i> New</a>
@endcan
</div>
</div>
@forelse ($roles as $role)
{!! Form::model($role, ['method' => 'PUT', 'route' => ['roles.update', $role->id ], 'class' => 'm-b']) !!}
@if($role->name === 'Admin')
@include('shared._permissions', [
'title' => $role->name .' Permissions',
'options' => ['disabled'] ])
@else
@include('shared._permissions', [
'title' => $role->name .' Permissions',
'model' => $role ])
@can('edit_roles')
{!! Form::submit('Save', ['class' => 'btn btn-primary']) !!}
@endcan
@endif
{!! Form::close() !!}
@empty
<p>No Roles defined, please run <code>php artisan db:seed</code> to seed some dummy data.</p>
@endforelse
@endsection
Let’s add resources/views/shared/_permissions.blade.php
template.
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="{{ isset($title) ? str_slug($title) : 'permissionHeading' }}">
<h4 class="panel-title">
<a role="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($user) ? '<span class="text-danger">(' . $user->getDirectPermissions()->count() . ')</span>' : '' !!}
</a>
</h4>
</div>
<div id="dd-{{ isset($title) ? str_slug($title) : 'permissionHeading' }}" class="panel-collapse collapse {{ $closed or 'in' }}" role="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($role) ) {
$per_found = $role->hasPermissionTo($perm->name);
}
if( isset($user)) {
$per_found = $user->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>
If you visit now /roles
you can find will be able to manage the roles and permission.
Permissions Management
Permissions are not going to be changed very often in most cases, you can just add them directly into the database. I am leaving the implementation for this. It’s simple CRUD, if you wanted you can implement it. One thing we can do to create a command which we can run to create permissions, something like php artisan auth:permission tasks
, which will create 'view_tasks', 'add_tasks', 'edit_tasks', 'delete_tasks'
the permissions for tasks model, and if we pass --remove
it will delete permissions on it.
Create our command by running php artisan make:command AuthPermissionCommand
.
class AuthPermissionCommand extends Command
{
protected $signature = 'auth:permission {name} {--R|remove}';
...
public function handle()
{
$permissions = $this->generatePermissions();
// check if its remove
if( $is_remove = $this->option('remove') ) {
// remove permission
if( Permission::where('name', 'LIKE', '%'. $this->getNameArgument())->delete() ) {
$this->warn('Permissions ' . implode(', ', $permissions) . ' deleted.');
} else {
$this->warn('No permissions for ' . $this->getNameArgument() .' found!');
}
} else {
// create permissions
foreach ($permissions as $permission) {
Permission::firstOrCreate(['name' => $permission ]);
}
$this->info('Permissions ' . implode(', ', $permissions) . ' created.');
}
// sync role for admin
if( $role = Role::where('name', 'Admin')->first() ) {
$role->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')));
}
}
Our command is ready, next let’s register it in Kernel, open the app/Console/Kernel.php and add.
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 permissions manually in the db, don’t forget to run
php artisan cache:forget spatie.permission.cache
, otherwise new permissions wont work.
Finally, we have a starter kit which you can use for any new project required roles and permissions. Check the source code & I hope you found it useful, let me know in the comments if you have any question.
Very nice, thanks for writing this. I’ll add a link to this tutorial in the readme of the package.
That will be great, thanks for simple and awesome package for laravel permissions
Really nice tutorial !
This helped me a lot with handling ACL in my new Application
Nice Tutorial. It is very helpful.
I added one custom permission directly to the database (not crud permission) and the template breaks. Do you have any solution for this?
You can always fallback to
@can('your_custom_permissions')
in blade template. same is true for controllerAuth::user()->can('your_custom_permissions')
or you can use authorized like this$this->authorize('your_custom_permissions');
I would suggest pick a naming convention for route and permission and stick to it, you can also match the
$abilities
array in Authorizable traits line number 15 for your specific need.If you need any further help, please share your custom route and some permissions you wanted to add. by default a permission name is made of
{controller_method}_{route_name}
see the trait.I just added a new permission as an example for a custom permission and the route with the role/permissions form broke.
I know how I can authorize against a custom permission, but i want the custom permission in the permissions view with the other permissions 🙂
ok, if you can share the permissions you wanted to add, i will try to reproduce it at my end to better understanding.
I need to add these directly in database right?
if you can give me the permissions you have added that will be very helpful to reproduce this error at my end.
I just added a new permission via Sequel Pro called custom_permission. nothing more.
After adding this permission the permission template breaks…
Worked out the issue. After adding a permission via Sequal Pro you need to run `php artisan cache:forget spatie.permission.cache`
Heya, If I try and add a custom permission called ‘access_staff_panel’ it would break the permissions blade saying . “There is no permission named `access_staff_panel` for guard `web`.” As mentioned I did this just using Sequal Pro, how would I go about adding a custom permission that I can assign to roles + users?
Nice tutorial, thank you! It has helped me get ACL working on my new app. I am experiencing one small issue though: Trying to use the auth:permission artisan command works for creating new permissions, but trying to use the –R or remove option results in “The “–R” option does not exist.” or “Too many arguments, expected arguments “command” “name”. respectively. Any ideas why I can’t specify remove?
hey Chris, you need to user
php artisan auth:permission Comment -R
or
php artisan auth:permission Comment –remove
to remove permissions.
Thank You very much 🙂
excellent tutorial, it showed me the way. i struck here, where in migrations when i see migrations it can create model_has_roles and model_has_permissions tables. But when i run the code i am getting errors like ‘base table or view not found. we don’t have tables like user_has_roles and user_has_permissions table. Please suggest. thank you in advance. thank you
Its seems you forgot to ran the migrations, please try running it but
php artisan migrate
or
php artisan migrate:refresh
or if you have cloned code from repo you can run the
php artisan db:seed
it will prompt u to refresh the migration.Let me know how it goes
Hey Saqueib,
very nice tutorial! Thanks a lot, will use this for my new app.
Quick question: As far as I can see, there is nothing prepared to make queries in a Controller based on user permissions.
For example on an edit view, include roles for admins, but not for normal users.
How would you do that?
Just rely on @can(‘admin’) in Blade, or actually do two seperate Eloquent queries for each user role to only include the data they are allowed to see?
hi @madsem:disqus you can query or check for permission in controller using
$user->can('assign_roles')
.To show the user roles for admin I would create a custom permission and assign it to admin role, and later in blade view i would check it by @can(‘assign_roles’) directive. don’t forget to run
php artisan cache:forget spatie.permission.cache
to clear the cache.got it, thanks 🙂
I think I wasn’t 100% clear with my question.
I meant: Would you even make Eloquent queries based on user roles, or just one query for all data a View needs, and then only use @can(‘permission’) in the Blade view to include/exclude data, or would you make multiple DB queries, one for each role? Like what do you think is best practice here 🙂
Saqueib I believe there are two small errors in the Git repo.
“`
UserController.php
} else {
// handle permissions
$user->syncPermissions($permissions);
}
“`
should be:
“`
…
}
// handle permissions
$user->syncPermissions($permissions);
“`
otherwise permissions are not correctly updated when you override them on a per user basis.
And in Handler.php you have commented out the render() method, which causes the auth check to throw an error when a user does an unauthorized action.
Great Tutorial, I am new in laravel and I am learning how to manage the roles and permissions situation, Can you help to understand how to add new permissions and roles? and to martch it with the controllers or routes, I can understand that. I hope you can help me. sorry for this noob cuestion.
Thanks, If you clone the repo you can add Roles by running
php artisan db:seed
. It will ask you to type roles in comma separate format, like ‘Admin,User’ will create these 2 roles. or you can manually add a Role directly in roles mysql table.For permissions you can use another command
php artisan auth:permission Post
, it will create permissions forPost
model.Now when you have got roles and permissions ready you can add Authorizable trait on a any resource controller to protect it via permissions.
…
class PostController extends Controller
{
use Authorizable;
…
I hope it helps you. If you have any question let me know
When I have upload live server then shown this error ,,
(1/1) FatalErrorException
syntax error, unexpected ‘:’, expecting ‘;’ or ‘{‘
in PermissionRegistrar.php (line 33)
Please help me , as soon as possible !!!
http://pos.hello-sylhet.com/
It seems something wrong with permissions, directories within the storage and the bootstrap/cache directories should be writable by your web server. Also run composer update on server
when I run this project in localhost then work perfectly but when I upload this project host in live server then given this error ,, please tell me how can I fix it !
(1/1) FatalErrorException
syntax error, unexpected ‘:’, expecting ‘;’ or ‘{‘
in PermissionRegistrar.php (line 33)
http://postest.hello-sylhet.com/
please reply !!
Your web server is running old version on PHP 5.3, try updating it to PHP >= 5.6.4, this should fix it
Great tut. Absolutely try this for a side project. Thanks S.
I am total newbie in laravel, I tried following this tutorial, when I run php artisan db:seed, I am getting this error,
[SymfonyComponentDebugExceptionFatalThrowableError]
Class ‘Permission’ not found
but my Permission model is defined , please help.
Thank You
It seems a Namespace Issue, make sure you import the Permission Model, by default it will be App\ Permission. Here is Permissions controller https://github.com/saqueib/roles-permissions-laravel/blob/master/app/Permission.php
How can i hide topnav menus.
You can edit master app layout to hide the menu, you can find it here https://github.com/saqueib/roles-permissions-laravel/blob/master/resources/views/layouts/app.blade.php#L29
Thanks for replying.
say i have topnav bar form which i want to hide some link based on user type. @can(‘custom_permission’) ..@endcan; I am confused with ‘custom_permission’. where from @can() gets this ‘custom_permission’.
{{trans(‘dashboard.security’)}}
@can(‘view_roles’)
{{trans(‘dashboard.role_management’)}}
@endcan
@can(‘view_users’)
{{trans(‘dashboard.user_management’)}}
@endcan
In above html inner links are working fine but how can i hide or show security on permission basis
Great tutorial, I have everything working until i get ‘This action is authorized’ for a particular route which i have given permission to
Am i missing something
When i open route like /patient/{patient},
Everything is fine
But when i visit routes like
/patient/{patient}/update,
If gives
‘This action is authorized’
Help please
Authorizable trait will work only if you follow the Laravel resource controller, for example route for update should look like this
PUT|PATCH | /patient/{patient}
You can always use
authorize('edit_patient')
in your controller methods if you don’t want to follow resourceful controller schemaHi,
for me route is ok but still give “This action is unauthorized.”
how to login as admin ?
When you run php artisan db:seed on successful run it will give you Admin email id, and default password is secret
When you run
php artisan db:seed
on successful run it will give you Admin email id, and default password is “secret”Hi. Great tutorial, I’m still working through it but encountered an issue. The check here: if ($exception instanceof AuthorizationException) in Handler.php is returning false when there is an auth error. When I dump $exception it looks like an instance of AuthorizationException so not sure why the check return false. I noticed also this line of code is commented out in the project github repo.
https://github.com/saqueib/roles-permissions-laravel/blob/master/app/Exceptions/Handler.php#L48
My bad. Forgot to add ‘use IlluminateAuthAccessAuthorizationException;’
it happens always, I bet you are using sublime text, in PHPStorm you will get instant hint if you forgot to import any class.
Ah, I am using SublimeText. I tried PHPStorm and liked it but need to invest a little time to get to know it better. I went back to Sublime for simplicity (but less power maybe). Would you recommend switching to PHPStorm?
I think PHPStorm is very helpful, you can see my earlier post on this http://qcode.in/code-editor-use-web-development/
Great, thanks. Will read your article
Fantastic tutorial and base ACL, thank you!
Hi Sequeib,
Thanks for wonderful tutorial, please help me.
when I use “php artisan migrate” so it gives error
[IlluminateDatabaseQueryException]
SQLSTATE[42000]: Syntax error or access violation: 1103 Incorrect table name ” (SQL: create table “ (id int unsigned not null auto_increment primary key, `name`
varchar(191) not null, `guard_name` varchar(191) not null, `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate utf8mb4_un
icode_ci)
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1103 Incorrect table name ”
Its seems you are not getting the table name from config file, please publish the vendor config using this.
php artisan vendor:publish --provider="SpatiePermissionPermissionServiceProvider" --tag="config"
Let me know how it goes.
I have successfully configure the above example and worked fine for laravel resource controller. But when i have added custom method in the controller the 403 error doesn’t work no protection over such url. But when i have added the such method in Abilities array in Authorizable traits it worked fine. But my question is, it is not good to added every custom method in the Abilities array. So what is the solution.
You don’t need to add in abilities array, that array is used if you want to change naming convention of routes altogether, by default its set for resource controller naming convention.
For any custom method authorization you should use
public function customeControllerAction() {
$this->authorize('your_custom_permission');
...
}
I hope this helps
Thanks now work fine. But still confuse in AuthorizationException Exception Handler when i have added the code above you wrote in Handler.php the permission doesn’t work, every user has access all url although i doesn’t give the permission for those user. What is the problem ?
Its simple, AuthorizationException Handler checks if its an Unauthorized Exception it returns redirect to home with a flash mag, and if its an ajax call it will return unauthorize msg as json. thats all its doing
(1/1) HttpException
This action is unauthorized.
May i know how to solve this error?
What should i do if i want user to be able to access the ACL?
You need to give user permissions to access that route, log in as admin and give permission. If you dont want ACL on a certain controller just remove Authorizable trait from controller and access will be allowed by default.
If you need any other help let me know with some code where you are getting this unauthorized exception.
You need to give user permissions to access that route, log in as admin and give permission. If you dont want ACL on a certain controller just remove Authorizable trait from controller and access will be allowed by default.
If you need any other help let me know with some code where you are getting this unauthorized exception.
Actually i am recovering a old project that use laravel-permission package, now i am able to access the role and user by commenting the Authorizable trait. Even if i login as admin i am not able to make changes in the role and user view.
try clearing cache by running
php artisan cache:forget spatie.permission.cache
. share some code so I can help you if problem still exists.Hi there, when I run the php artisan db:seed, everything works normal till the:
“Enter roles in comma separate format. [Admin,User]:”
when I entered the roles, it show something like this:
[SymfonyComponentDebugExceptionFatalThrowableError]
Parse error: syntax error, unexpected ‘;’, expecting function (T_FUNCTION)
I rechecked the DatabaseSeeder.php and everything look fine, but maybe I miss something
and btw, nice tutorial, and thank you.
I have a little problem
(1/1) HttpException
This action is unauthorized.
This happens when i open users view, i followed all this tutorial and i was comparing between your source code and mine, I can’t find the solution.
https://github.com/Majunko/Test
What can i do?
Thanks for sharing code, here is the issue, you have translated the names of routes and they are not updated in view files. Change names in these files.
# routes/web.php
Route::resource('usuarios', 'UserController'); // change users to usuarios
// update the route names in views
# resources/views/layouts/app.blade.php line:51-57
@can('ver_usuarios')
Users
@endcan
# resources/views/user/index.blade.php line:12,43
Create
@include('shared._actions', [
'entity' => 'usuarios',
'id' => $item->id
])
This will show you the users list, but you will be needed to update it everywhere, in Form action and in other views also.
created a pull request, merge it on github to get the fix.
I hope it helps, let me know how it goes
Yeah it helps a lot, Thank you Saqueib for taking your time for help me. Now everything goes very fine.
Great tutorial, you’re amazing.
Regards.
Greetings from Colombia. I try to implement step by step this tutorial, but when I apply the command: “php artisan db:seed” I get the errors as imagen shows. Any idea?
https://uploads.disquscdn.com/images/6a09b3193e4b28a99a0b3490f5519324aade44713dab9697b1b2088cd4e6e676.jpg
add this on your DatabaseSeeder :
use AppPermission;
use AppRole;
Thaxs, It helped. Have a nice day!
Hiiiii
this is a very good tutorial
but i can’t undertood
where i add Authorizable Trait
Please guide me.
Thanks
You should add on any resource controller you want to be be authorized, you can create a resource controller using php artisan make:controller ProductController – r
Hope this helps
You can simply create file for trait under App(Authorizable.php) just like the model.
Im trying to creat post, but i found error when i click save. any idea…what it causes?
https://uploads.disquscdn.com/images/ba7224799b9ba1002e1ced234e074d716a7b1b54fdb78063c6827ecec51db603.jpg
im creating new role for other user, but when i give access for editing and deleting post in role https://uploads.disquscdn.com/images/ca9fa5241faf8d055d69a9fbdaed193053b6506a2637e50a097a2e63145a16d6.jpg , the action icon wont show. any idea what it cause?
please share the blade @can directive for this button in your view, and make sure you have given user that role, also update user by editing it.
dunno why, but when i restart the server….everything works fine :D…. thanks
It could be the caching. Glad it’s working
Sanchez, i getting this error, please help me
Hi, I made extra column for the role table, called role_desc and it already work when I add new role with its description. It also already displayed at the Role page. But, when I try to edit user, it gave an error, undefined variable “role”. So my question is, how to make it work at user edit page?
for example, “Your Current role is Admin. (Role Description: …).
At _permissions.blade.php, I used “Role Description: {{ $role->role_desc }}” to show role description.
Thank you.
Thats strange If you can, just create repo and push your code I can see, must be something related to passing $role data to view
Thx for your time, the code exactly the same as the tutorial provided, I only add the “Role Description: {{ $role->role_desc }}” right above “@foreach($permissions as $perm)”at _permissions.blade.php (first image) and the second image for the RoleController which I change at little at store method.
https://uploads.disquscdn.com/images/4bc37615d83e8a724bf1447be910fec24d81e36aaa07543143563db6267c19d4.png
https://uploads.disquscdn.com/images/a1390bf373f347cc0588aed7964394a5ec74d47bcac7570a16ff0a726cfa7897.png
I see, you have called the $role variable before its initialized, if you see on line 17 i am checking if $role is set before doing anything with it.
You can either more Role Description in side Line 17 if block or just check isset($role) before calling $role->role_desc.
One side note I have used same
_permissions.blade.php
partial in user edit and role edit, thats why i needed to check if $role is set.I got it now, thx for your time.
When using custom guard like admin. And put the Authorizable trait in controller it doesn’t work. i get 403 exception, how to fix this one.
you should try to set your guard default if possible
(config('auth.default.guard')
or you can check this to see how you can use multiple guards https://github.com/spatie/laravel-permission#using-multiple-guardshi Saqueib i used default guard for front login and my role base login is backend so how to fix for backend. if i have change default guard to admin in auth.php config file its work, but i don’t want to change default one.
@somenet77:disqus i have same issue. are You has resolve?
Hi,
Thanks for a great tutorial.
When I run the command “php artisan db:seed” I get this error:
[InvalidArgumentException]
Unable to locate factory with name [default] [AppPost].
Any idea why?
Either you forgot to define a factory for
AppPost
model or you haven’t imported it at the top ofDatabaseSeeder
. Share you database/seeds/DatabaseSeeder.php on https://pastebin.com/ file if problem exists.I forgot to define a factory for AppPost model, it’s all working fine now.
Thanks for your reply.
How you fix it? Tanks
How define a factory?
Hi,
I don’t get the flash messages appearing when I do something, like flash(‘Role Added’);
What am I missing?
Check your layout file, it must include the
@include('flash::message')
view partial.@include('flash::message')
Also include the JS part to show it
$(function () {
// flash auto hide
$('#flash-msg .alert').not('.alert-danger, .alert-important').delay(6000).slideUp(500);
})
Check here for layout https://github.com/saqueib/roles-permissions-laravel/blob/master/resources/views/layouts/app.blade.php#L114
Many thanks.
Hi again,
If I visit an invalid URL like /users/10/edit (when user 10 does not exist), I get the attached error rather than the exception handling, any ideas? https://uploads.disquscdn.com/images/f785476fa84612935ce34a760a302ec1b611fcf6a79bf8e121cc1289d7b78199.png
Maybe your logged in user dont have permission to edit a user, also you should change
UserController@edit
to useUser::findOrFail($id)
instead$user = User::find($id);
which will give 404 if user doesn’t exists, https://github.com/saqueib/roles-permissions-laravel/blob/master/app/Http/Controllers/UserController.php#L91I have the code included you specified and the user can edit users.
If the user has permissions to edit a user and I say edit user 3, the user account edit appears. If I then change the URL in the browser to a user that doesn’t exist (like user 31) then I get an error saying:
Trying to get property of non-object (View: /resources/views/user/edit.blade.php), shouldn’t that get caught by the exception handler?
This is really cool!
I have bumped into an issue, after adding other permissions manually, i couldn’t manage to make them also default to the Admin role, and it also seems like i can’t check(tick) them. Can someone help me out!
Regards!
It seems cache issue, run
php artisan cache:forget spatie.permission.cache
it should fix itHi, Great post. but while i am using
php artisan vendor:publish –provider=”SpatiePermissionPermissionServiceProvider” –tag=”migrations”
this command its showing me an exception
PHP Fatal error: Class ‘SpatiePermissionPermissionServiceProvider’ not found in C:rplvendorlaravelframeworksrcIlluminateFoundationProviderRepository.php on line 208
[SymfonyComponentDebugExceptionFatalErrorException]
Class ‘SpatiePermissionPermissionServiceProvider’ not found
Kindly help me out. Thanks in advance
As it says, you need to install add
SpatiePermissionPermissionServiceProvider::class,
In config/app.php providers array, currently laravel is not able to find this provider binding
Thanks for your time.
kindly check my code. and help me
env(‘APP_NAME’, ‘Laravel’),
/*
|————————————————————————–
| Application Environment
|————————————————————————–
|
| This value determines the “environment” your application is currently
| running in. This may determine how you prefer to configure various
| services your application utilizes. Set this in your “.env” file.
|
*/
‘env’ => env(‘APP_ENV’, ‘production’),
/*
|————————————————————————–
| Application Debug Mode
|————————————————————————–
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
‘debug’ => env(‘APP_DEBUG’, false),
/*
|————————————————————————–
| Application URL
|————————————————————————–
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
| your application so that it is used when running Artisan tasks.
|
*/
‘url’ => env(‘APP_URL’, ‘http://localhost’),
/*
|————————————————————————–
| Application Timezone
|————————————————————————–
|
| Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. We have gone
| ahead and set this to a sensible default for you out of the box.
|
*/
‘timezone’ => ‘UTC’,
/*
|————————————————————————–
| Application Locale Configuration
|————————————————————————–
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/
‘locale’ => ‘en’,
/*
|————————————————————————–
| Application Fallback Locale
|————————————————————————–
|
| The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of
| the language folders that are provided through your application.
|
*/
‘fallback_locale’ => ‘en’,
/*
|————————————————————————–
| Encryption Key
|————————————————————————–
|
| This key is used by the Illuminate encrypter service and should be set
| to a random, 32 character string, otherwise these encrypted strings
| will not be safe. Please do this before deploying an application!
|
*/
‘key’ => env(‘APP_KEY’),
‘cipher’ => ‘AES-256-CBC’,
/*
|————————————————————————–
| Logging Configuration
|————————————————————————–
|
| Here you may configure the log settings for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Settings: “single”, “daily”, “syslog”, “errorlog”
|
*/
‘log’ => env(‘APP_LOG’, ‘single’),
‘log_level’ => env(‘APP_LOG_LEVEL’, ‘debug’),
/*
|————————————————————————–
| Autoloaded Service Providers
|————————————————————————–
|
| The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications.
|
*/
‘providers’ => [
/*
* Laravel Framework Service Providers…
*/
IlluminateAuthAuthServiceProvider::class,
IlluminateBroadcastingBroadcastServiceProvider::class,
IlluminateBusBusServiceProvider::class,
IlluminateCacheCacheServiceProvider::class,
IlluminateFoundationProvidersConsoleSupportServiceProvider::class,
IlluminateCookieCookieServiceProvider::class,
IlluminateDatabaseDatabaseServiceProvider::class,
IlluminateEncryptionEncryptionServiceProvider::class,
IlluminateFilesystemFilesystemServiceProvider::class,
IlluminateFoundationProvidersFoundationServiceProvider::class,
IlluminateHashingHashServiceProvider::class,
IlluminateMailMailServiceProvider::class,
IlluminateNotificationsNotificationServiceProvider::class,
IlluminatePaginationPaginationServiceProvider::class,
IlluminatePipelinePipelineServiceProvider::class,
IlluminateQueueQueueServiceProvider::class,
IlluminateRedisRedisServiceProvider::class,
IlluminateAuthPasswordsPasswordResetServiceProvider::class,
IlluminateSessionSessionServiceProvider::class,
IlluminateTranslationTranslationServiceProvider::class,
IlluminateValidationValidationServiceProvider::class,
IlluminateViewViewServiceProvider::class,
SpatiePermissionPermissionServiceProvider::class,
LaracastsFlashFlashServiceProvider::class,
CollectiveHtmlHtmlServiceProvider::class,
/*
* Package Service Providers…
*/
LaravelTinkerTinkerServiceProvider::class,
/*
* Application Service Providers…
*/
AppProvidersAppServiceProvider::class,
AppProvidersAuthServiceProvider::class,
// AppProvidersBroadcastServiceProvider::class,
AppProvidersEventServiceProvider::class,
AppProvidersRouteServiceProvider::class,
],
/*
|————————————————————————–
| Class Aliases
|————————————————————————–
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are “lazy” loaded so they don’t hinder performance.
|
*/
‘aliases’ => [
‘App’ => IlluminateSupportFacadesApp::class,
‘Artisan’ => IlluminateSupportFacadesArtisan::class,
‘Auth’ => IlluminateSupportFacadesAuth::class,
‘Blade’ => IlluminateSupportFacadesBlade::class,
‘Broadcast’ => IlluminateSupportFacadesBroadcast::class,
‘Bus’ => IlluminateSupportFacadesBus::class,
‘Cache’ => IlluminateSupportFacadesCache::class,
‘Config’ => IlluminateSupportFacadesConfig::class,
‘Cookie’ => IlluminateSupportFacadesCookie::class,
‘Crypt’ => IlluminateSupportFacadesCrypt::class,
‘DB’ => IlluminateSupportFacadesDB::class,
‘Eloquent’ => IlluminateDatabaseEloquentModel::class,
‘Event’ => IlluminateSupportFacadesEvent::class,
‘File’ => IlluminateSupportFacadesFile::class,
‘Gate’ => IlluminateSupportFacadesGate::class,
‘Hash’ => IlluminateSupportFacadesHash::class,
‘Lang’ => IlluminateSupportFacadesLang::class,
‘Log’ => IlluminateSupportFacadesLog::class,
‘Mail’ => IlluminateSupportFacadesMail::class,
‘Notification’ => IlluminateSupportFacadesNotification::class,
‘Password’ => IlluminateSupportFacadesPassword::class,
‘Queue’ => IlluminateSupportFacadesQueue::class,
‘Redirect’ => IlluminateSupportFacadesRedirect::class,
‘Redis’ => IlluminateSupportFacadesRedis::class,
‘Request’ => IlluminateSupportFacadesRequest::class,
‘Response’ => IlluminateSupportFacadesResponse::class,
‘Route’ => IlluminateSupportFacadesRoute::class,
‘Schema’ => IlluminateSupportFacadesSchema::class,
‘Session’ => IlluminateSupportFacadesSession::class,
‘Storage’ => IlluminateSupportFacadesStorage::class,
‘URL’ => IlluminateSupportFacadesURL::class,
‘Validator’ => IlluminateSupportFacadesValidator::class,
‘View’ => IlluminateSupportFacadesView::class,
‘Form’ => CollectiveHtmlFormFacade::class,
‘Html’ => CollectiveHtmlHtmlFacade::class,
],
];
share your composer.json file
Thanks for reply. kindly check composser.json
{
“name”: “laravel/laravel”,
“description”: “The Laravel Framework.”,
“keywords”: [“framework”, “laravel”],
“license”: “MIT”,
“type”: “project”,
“require”: {
“php”: “>=5.6.4”,
“laravel/framework”: “5.4.*”,
“laravel/tinker”: “~1.0”,
“spatie/laravel-permission”: “^2.1”,
“laracasts/flash”: “^3.0”,
“laravelcollective/html”: “^5.3.0”,
},
“require-dev”: {
“fzaninotto/faker”: “~1.4”,
“mockery/mockery”: “0.9.*”,
“phpunit/phpunit”: “~5.7”
},
“autoload”: {
“classmap”: [
“database”
],
“psr-4”: {
“App\”: “app/”
}
},
“autoload-dev”: {
“psr-4”: {
“Tests\”: “tests/”
}
},
“scripts”: {
“post-root-package-install”: [
“php -r “file_exists(‘.env’) || copy(‘.env.example’, ‘.env’);””
],
“post-create-project-cmd”: [
“php artisan key:generate”
],
“post-install-cmd”: [
“Illuminate\Foundation\ComposerScripts::postInstall”,
“php artisan optimize”
],
“post-update-cmd”: [
“Illuminate\Foundation\ComposerScripts::postUpdate”,
“php artisan optimize”
]
},
“config”: {
“preferred-install”: “dist”,
“sort-packages”: true,
“optimize-autoloader”: true
}
}
run composer update
‘providers’ => [
/*
* Laravel Framework Service Providers…
*/
IlluminateAuthAuthServiceProvider::class,
IlluminateBroadcastingBroadcastServiceProvider::class,
IlluminateBusBusServiceProvider::class,
IlluminateCacheCacheServiceProvider::class,
IlluminateFoundationProvidersConsoleSupportServiceProvider::class,
IlluminateCookieCookieServiceProvider::class,
IlluminateDatabaseDatabaseServiceProvider::class,
IlluminateEncryptionEncryptionServiceProvider::class,
IlluminateFilesystemFilesystemServiceProvider::class,
IlluminateFoundationProvidersFoundationServiceProvider::class,
IlluminateHashingHashServiceProvider::class,
IlluminateMailMailServiceProvider::class,
IlluminateNotificationsNotificationServiceProvider::class,
IlluminatePaginationPaginationServiceProvider::class,
IlluminatePipelinePipelineServiceProvider::class,
IlluminateQueueQueueServiceProvider::class,
IlluminateRedisRedisServiceProvider::class,
IlluminateAuthPasswordsPasswordResetServiceProvider::class,
IlluminateSessionSessionServiceProvider::class,
IlluminateTranslationTranslationServiceProvider::class,
IlluminateValidationValidationServiceProvider::class,
IlluminateViewViewServiceProvider::class,
SpatiePermissionPermissionServiceProvider::class,
LaracastsFlashFlashServiceProvider::class,
CollectiveHtmlHtmlServiceProvider::class,
/*
* Package Service Providers…
*/
LaravelTinkerTinkerServiceProvider::class,
/*
* Application Service Providers…
*/
AppProvidersAppServiceProvider::class,
AppProvidersAuthServiceProvider::class,
// AppProvidersBroadcastServiceProvider::class,
AppProvidersEventServiceProvider::class,
AppProvidersRouteServiceProvider::class,
],
/*
|————————————————————————–
| Class Aliases
|————————————————————————–
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are “lazy” loaded so they don’t hinder performance.
|
*/
‘aliases’ => [
‘App’ => IlluminateSupportFacadesApp::class,
‘Artisan’ => IlluminateSupportFacadesArtisan::class,
‘Auth’ => IlluminateSupportFacadesAuth::class,
‘Blade’ => IlluminateSupportFacadesBlade::class,
‘Broadcast’ => IlluminateSupportFacadesBroadcast::class,
‘Bus’ => IlluminateSupportFacadesBus::class,
‘Cache’ => IlluminateSupportFacadesCache::class,
‘Config’ => IlluminateSupportFacadesConfig::class,
‘Cookie’ => IlluminateSupportFacadesCookie::class,
‘Crypt’ => IlluminateSupportFacadesCrypt::class,
‘DB’ => IlluminateSupportFacadesDB::class,
‘Eloquent’ => IlluminateDatabaseEloquentModel::class,
‘Event’ => IlluminateSupportFacadesEvent::class,
‘File’ => IlluminateSupportFacadesFile::class,
‘Gate’ => IlluminateSupportFacadesGate::class,
‘Hash’ => IlluminateSupportFacadesHash::class,
‘Lang’ => IlluminateSupportFacadesLang::class,
‘Log’ => IlluminateSupportFacadesLog::class,
‘Mail’ => IlluminateSupportFacadesMail::class,
‘Notification’ => IlluminateSupportFacadesNotification::class,
‘Password’ => IlluminateSupportFacadesPassword::class,
‘Queue’ => IlluminateSupportFacadesQueue::class,
‘Redirect’ => IlluminateSupportFacadesRedirect::class,
‘Redis’ => IlluminateSupportFacadesRedis::class,
‘Request’ => IlluminateSupportFacadesRequest::class,
‘Response’ => IlluminateSupportFacadesResponse::class,
‘Route’ => IlluminateSupportFacadesRoute::class,
‘Schema’ => IlluminateSupportFacadesSchema::class,
‘Session’ => IlluminateSupportFacadesSession::class,
‘Storage’ => IlluminateSupportFacadesStorage::class,
‘URL’ => IlluminateSupportFacadesURL::class,
‘Validator’ => IlluminateSupportFacadesValidator::class,
‘View’ => IlluminateSupportFacadesView::class,
‘Form’ => CollectiveHtmlFormFacade::class,
‘Html’ => CollectiveHtmlHtmlFacade::class,
],
];
Thanks for this write up, you saved me many hours of work. I’m having a little problem with the Authorizable Trait tho. right now, when I try to access a controller that uses the trait (let’s say ExampleController), I get “Undefined method “…Controllers\ExampleController::authorize”. Please kindly support.
Thats strange, make sure you ExampleController extends base
AppHttpControllersController.php
class ExampleController extends Controller {
...
}
Since
authorize()
method comes from AuthorizesRequests trait.Let me know how it goes.
Thank you for the quick reply. You are right, I wasn’t extending my base controller, so I couldn’t access the AuthorizesRequests trait. that’s fixed. thank you. 🙂
Sir, do you have a tutorial base on native laravel auth? Can you make it multiple role permission using the native way? Packages has its own disadvantages I’m looking into some native way. There are some but it doesn’t fit on what Im looking for. Btw, you have the better explaination based on spatie . Thanks for this
Great tutorials. Wouldn’t it be better to use a middleware ? You would expect to receive a 403 but if the data doesn’t passe validation you will get a 422 instead. I made a quick gist based on your code. https://gist.github.com/lamberttraccard/c0ab9c1ff7b52bd4eb9d8fa188c4470c
Thats great idea, there is always more than one way to solve a problem. Thanks for sharing your gist
Hi,
One thing i can’t understand is in the Trait Authorizable
when we call $this->authorize($ability);
then we call the Laravel’s permission,and not the spatie one’s
Then for every route i get an Unauthorized Exception, because the $ability is unknow from Laravel core, just known by Spatie’s Tables
I would imagine in the trait a call to a Spatie Authorize method.
Do you know how it works ?
Thx
If i run php artisan auth:permission appear
[SymfonyComponentConsoleExceptionRuntimeException]
Not enough arguments (missing: “name”).
How to fix? Thank You
Its strange, please try with other name also
php artisan auth:permission appears
You can seed the data which will create admin user.
php artisan db:seed
Thank yo for the article. Great stuff.
Quick question… where should I change the migration file to accomodate UUID for the user_id? In my users table, the users have UUID..
thanks nikalai, you can update migration to add any field on users migration
https://github.com/saqueib/roles-permissions-laravel/blob/master/database/migrations/2014_10_12_000000_create_users_table.php#L18
you should also match it in the model factory
https://github.com/saqueib/roles-permissions-laravel/blob/master/database/factories/ModelFactory.php#L22
Thanks for the quick reply.
In my User model I have:
// Do not use auto-incrementing
public $incrementing = false;
and in the migration, I have the field set to UUID.
But when I run php artisan migrate:refresh –seed, I get the following error:
[IlluminateDatabaseQueryException]
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: “b2038760-bf9e-11e7-a022-6b5e6a138514” (SQL: insert into “model_has_roles” (“model_id”, “model_type
“, “role_id”) values (b2038760-bf9e-11e7-a022-6b5e6a138514, AppUser, 1))
Is it something I should o in the create_permission_tables.php migration?
[PDOException]
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: “b2038760-bf9e-11e7-a022-6b5e6a138514”
oh I see, in this case you will need to change the migration for CreatePermissionTables, out of the box it setup to use int, tweak all the reference to use uuid instead of integer column.
I’ve replaced all the integer with UUID. Nor I run into a different error:
[IlluminateDatabaseQueryException]
SQLSTATE[42830]: Invalid foreign key: 7 ERROR: there is no unique constraint matching given keys for referenced table “permissions” (SQL: alter table “model_has_permissions” add constraint
“model_has_permissions_permission_id_foreign” foreign key (“permission_id”) references “permissions” (“id”) on delete cascade)
Amazing tutorial, I have some problems though. First, when a user is not authorized to see access a resource, I get this error:
Symfony Component HttpKernel Exception AccessDeniedHttpException
This action is unauthorized.
It seems that the Exception handler isn’t doing anything at all, I should be redirected with a flash message, right?
Second issue is that when I try to create a new user, I get this error:
Symfony Component HttpKernel Exception MethodNotAllowedHttpException
No message
This happens when I hit the submit button.
Please let me know if you want me to share my code with you. Thanks a lot.
Hi, this is bug?
I have allow user for delete_users and record found in table role_has_permissions
then in file user/index.blade.php edited like this
@can(‘edit_users’, ‘delete_users’)
@include(‘shared._actions’, [
‘entity’ => ‘users’,
‘id’ => $item->id
])
@endcan
nothing show action delete
Yes, it is a bug. @can syntax does not allow you to pass two permissions like that. It’s invalid. The second parameter supported should be a Model instance. You can do this instead.
@if (Gate::check(‘edit_users’) || Gate::check(‘delete_users’))
….
@endif
^C
C:UsersDineshDownloadsNew folder (2)roles-permissions-laravel-master>php artisan db:seed
Do you wish to refresh migration before seeding, it will clear all old data ? (yes/no) [no]:
> yes
Rolling back: 2017_04_30_014352_create_permission_tables
Rolled back: 2017_04_30_014352_create_permission_tables
Rolling back: 2017_04_30_012311_create_posts_table
Rolled back: 2017_04_30_012311_create_posts_table
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back: 2014_10_12_100000_create_password_resets_table
Rolling back: 2014_10_12_000000_create_users_table
Rolled back: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrating: 2017_04_30_012311_create_posts_table
Migrated: 2017_04_30_012311_create_posts_table
Migrating: 2017_04_30_014352_create_permission_tables
Migrated: 2017_04_30_014352_create_permission_tables
Data cleared, starting from blank database.
Default Permissions added.
Create Roles for user, default is admin and user? [y|N] (yes/no) [yes]:
>
??????? (yes/no) how to set admin login user login?
how to check box permission saved, please help me
got the output. awesome tutorial thanks and please update more different roles and permission based on model
Nice tutorial
Call to undefined method IlluminateDatabaseQueryBuilder::defaultPermissions()
I have error when I run db:seed, what is the prolem?
thanks
It looks you haven’t imported the App /Permission Model, it’s currently using packages permission model which don’t have defaultPermissions method
Is it possible to use the roles with the API:
Route::middleware(‘auth:api’)->get(‘/user’, function (Request $request)
How can i test it on Postman?
Thank you so much
Call to undefined method IlluminateDatabaseQueryBuilder::defaultPermissions()
I have error when I run db:seed, what is the prolem?
Thanks….
It looks you haven’t imported the App /Permission Model, it’s currently using packages permission model which don’t have defaultPermissions method
if using table admin do not use table user what is it possible? if you can what to change in the settings?
Sorry I didn’t get your question?
If you mean to use admin table to store users instead of users table you can do it by changing the App/User class property protected $table = admins’;
Let me know if you need help. You can check out Eloquent naming convention here https://laravel.com/docs/5.5/eloquent#eloquent-model-conventions
Oke, Thanks a lot of.
on debug get. i have error below :
array:4 [▼
“ability” => “view_role”
“result” => false
“user” => 1
“arguments” => “[]”
]
what wrong, i has follow stap by stap tutorial. i use laravel 5.5
help me : authorize($ability) not wokfing if use guard admin. on Gate error message
array:4 [▼
“ability” => “view_order”
“result” => false
“user” => 1
“arguments” => “[]”
]
i use guard web for customer (use table users) and guard admin for administrator (use table admins). why result in gate always false.
[SymfonyComponentConsoleExceptionCommandNotFoundException]
Command “make:model” is not defined.
Did you mean one of these?
make:seeder
make:migration
i get this error trying to run this command
php artisan make:model Post -m -c –resource
Run php artisan make:model Post -mr
Hey Saqueib, very nice tutorial! It works very well!
I just have one question regarding the validation rule of an update method.
How to flash a error message if the validation fails. I want to keep the syntax with
$this->validate
Is it possible to use something like this?
$test = $this->validate($request, [
'name' => 'required|min:2|max:255'
]);
if( $test->failed() )
{
flash->error( /*The error*/ )
}
else
{
/*Proceed to validation*/
}
Or I am obligated to use the “old” method by using the Validator model like this
$validator = Validator::make($request->all(), [
'name' => 'required|min:2|max:255'
]);
if ($validator->fails()) /*...*/
Very good post.
Thanks.
I have an error : if I check edit_posts and uncheck the others permissions for the User role.
When I try to access to http://domain/public/posts/4/edit
I can see the post, but when I want to save my modification, I have the error NotFoundHttpException in Handler.php line 131 : No query results for model [AppPost] 4.
In my application I wish to not permit to show a list of posts for an user, but with a given url I want to permit user to edit a certain post.
Can you help me ?