Permissions and roles for Laravel 9.20 and up.
Install package via composer:
composer require kerigard/laravel-roles
Publish the configuration and migration files using the vendor:publish
artisan command:
php artisan vendor:publish --provider="Kerigard\LaravelRoles\RolesServiceProvider"
Customize the roles.php
configuration file according to your requirements. After that run the migrations:
php artisan migrate
To start using permission and role checking, your User model must use the Kerigard\LaravelRoles\Traits\HasRoles
and Kerigard\LaravelRoles\Traits\HasPermissions
traits:
use Kerigard\LaravelRoles\Traits\HasPermissions;
use Kerigard\LaravelRoles\Traits\HasRoles;
class User extends Authenticatable
{
use HasPermissions;
use HasRoles;
}
It is not necessary to connect both traits at the same time.
Create roles and permissions, after which create a relationship between them:
use Kerigard\LaravelRoles\Models\Permission;
use Kerigard\LaravelRoles\Models\Role;
$role = Role::create(['name' => 'Manager', 'slug' => 'manager']);
$permission = Permission::create(['name' => 'Edit articles', 'slug' => 'edit-articles']);
$role->attachPermission($permission);
You can override models through a config file.
Connect a role or permission to a user:
$user->attachRole(1);
$user->attachRole($adminRole);
$user->attachRole('super-admin');
$user->attachRole([1, $adminRole, 'manager']);
$user->attachPermission(1);
$user->attachPermission($editPostsPermission);
$user->attachPermission('edit-articles');
$user->attachPermission([1, $editPostsPermission, 'edit-articles']);
You can disable a role or permission for a user:
$user->detachRole(1);
$user->detachRole($adminRole);
$user->detachRole('super-admin');
$user->detachRole([1, $adminRole, 'manager']);
$user->detachAllRoles();
$user->detachPermission(1);
$user->detachPermission($editPostsPermission);
$user->detachPermission('edit-articles');
$user->detachPermission([1, $editPostsPermission, 'edit-articles']);
$user->detachAllPermissions();
Or just sync the specified roles or permissions. Any roles or permissions that are not listed will be disabled:
$user->syncRoles(1);
$user->syncRoles($adminRole);
$user->syncRoles('super-admin');
$user->syncRoles([1, $adminRole, 'manager']);
$user->syncPermissions(1);
$user->syncPermissions($editPostsPermission);
$user->syncPermissions('edit-articles');
$user->syncPermissions([1, $editPostsPermission, 'edit-articles']);
Use this method if you don't want old roles or permissions to be disabled when syncing:
$user->syncRolesWithoutDetaching($role);
$user->syncPermissionsWithoutDetaching($permission);
To check for permission, run:
$user->hasPermission('edit-articles');
$user->hasPermission(1);
$user->hasPermission($permission);
// has all permissions
$user->hasPermission(['edit-articles', 'register-articles']);
// has any permissions
$user->hasAnyPermission(['edit-articles', 'register-articles']);
$user->doesNotHasPermission($permission);
$user->doesNotHasAnyPermission(['edit-articles', 'register-articles']);
// or check that the role contains the permission
$role->hasPermission('edit-articles');
All permissions are registered with Laravel Gates, so you can use the can
function:
$user->can('edit-articles');
$user->can(['edit-articles', 'register-articles']);
$user->canAny(['edit-articles', 'register-articles']);
In a controller, you can use the authorize
function to throw an exception if the user doesn't have permissions:
class PostController extends Controller
{
public function index()
{
$this->authorize('view-posts');
return Post::all();
}
}
To check if a role exists, run:
$user->hasRole('manager');
$user->hasRole(1);
$user->hasRole($role);
// has all roles
$user->hasRole(['manager', 'admin']);
// kas any roles
$user->hasAnyRole(['manager', 'admin']);
$user->doesNotHasRole($role);
$user->doesNotHasAnyRole(['manager', 'admin']);
If you want to check the role in the controller and raise an exception if it is missing, then you need to replace the trait import in the app\Http\Controllers\Controller.php
file:
// from
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
// to
use Kerigard\LaravelRoles\Traits\AuthorizesRequests;
After that, you can use the authorizeRole
function in all controllers to check the role:
class PostController extends Controller
{
public function index()
{
$this->authorizeRole('editor');
return Post::all();
}
}
You can use directives in blade files to write conditions conveniently:
@can('edit-articles')
//
@endcan
@canany(['edit-articles', 'register-articles'])
//
@endcanany
@is('manager')
//
@endis
@isany(['manager', 'admin'])
//
@endisany
In the app/Http/Kernel.php
file, you can specify a middleware for checking roles and permissions:
protected $routeMiddleware = [
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'is' => \Kerigard\LaravelRoles\Middlewares\AuthorizeRole::class,
];
Then you can secure your routes:
Route::put('users', [UserController::class, 'update'])->middleware('can:edit-users');
// or
Route::put('users', [UserController::class, 'update'])->can('edit-users');
Route::get('users', [UserController::class, 'index'])->middleware('is:admin');
// or
Route::get('users', [UserController::class, 'index'])->is('admin');
When throwing exceptions by default, Laravel returns a 403
error code with the message This action is unauthorized
. You can specify your own error codes and messages for each role and permission:
Role::create([
'name' => 'Admin',
'slug' => 'admin',
'status' => 404,
'message' => 'Not found',
]);
Permission::create([
'name' => 'Edit users',
'slug' => 'edit-users',
'status' => 404,
'message' => 'Not found',
]);
In the configuration, you can enable the super admin role. For users with this role, all permissions and role checks will be true
.
Please see the CHANGELOG for more information on what has changed recently.
MIT. Please see the LICENSE FILE for more information.