ACL stands for Access Control List. ACL roles and permissions are very important if you are making big application
to implement User Roles and Permissions(ACL) using spatie/laravel-permission
composer package.
Laravel permission allows you to manage user permissions and roles in a database.
To use Laravel 11.0 or higher, you need Laravel Permission Package with 6.0 or higher.
Please follow these steps and you should be ready to start with Laravel Permission:
config/permission.php
file. If you already have a file by that name, you must rename or remove it.composer require spatie/laravel-permission
bootstrap/providers.php
file:'providers' => [
...
Spatie\Permission\PermissionServiceProvider::class,
];
config/permission.php
config file with below command:php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
config/permission.php
config file and set 'teams' => true
, if you want to use a custom foreign key for teams you must change team_foreign_key
.php artisan optimize:clear
php artisan config:clear
php artisan migrate
You can view the default config file contents at config/permission.php
First, add the Spatie\Permission\Traits\HasRoles
trait to your User
model(s):
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable{
use HasRoles;
...
}
This package allows for users to be associated with permissions and roles. Every role is associated with multiple permissions. A Role
and a Permission
are regular Eloquent models. They require a name
and can be created like this:
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);
A permission can be assigned to a role using 1 of these methods:
$role->givePermissionTo($permission);
$permission->assignRole($role);
Multiple permissions can be synced to a role using one of these methods:
$role->syncPermissions($permissions);
$permission->syncRoles($roles);
A permission can be removed from a role using 1 of these methods:
$role->revokePermissionTo($permission);
$permission->removeRole($role);
If you're using multiple guards the guard_name
attribute needs to be set as well. Read about it in the using multiple guards section of the readme.
The HasRoles
trait adds Eloquent relationships to your models, which can be accessed directly or used as a base query:
// get a list of all permissions directly assigned to the user
$permissionNames = $user->getPermissionNames(); // collection of name strings
$permissions = $user->permissions; // collection of permission objects
// get all permissions for the user, either directly, or from roles, or from both
$permissions = $user->getDirectPermissions();
$permissions = $user->getPermissionsViaRoles();
$permissions = $user->getAllPermissions();
// get the names of the user's roles
$roles = $user->getRoleNames(); // Returns a collection
The HasRoles
trait also adds a role
scope to your models to scope the query to certain roles or permissions:
$users = User::role('writer')->get(); // Returns only users with the role 'writer'
The role
scope can accept a string, a \Spatie\Permission\Models\Role
object or an \Illuminate\Support\Collection
object.
The same trait also adds a scope to only get users that have a certain permission.
$users = User::permission('edit articles')->get(); // Returns only users with the permission 'edit articles' (inherited or directly)
The scope can accept a string, a \Spatie\Permission\Models\Permission
object or an \Illuminate\Support\Collection
object.
You can create a role or permission from the console with artisan commands.
php artisan permission:create-role writer
php artisan permission:create-permission "edit articles" web
When creating roles you can also create and link permissions at the same time:
php artisan permission:create-role writer web "create articles|edit articles"
When creating roles with teams enabled you can set the team id by adding the --team-id
parameter:
php artisan permission:create-role --team-id=1 writer
php artisan permission:create-role writer api --team-id=1
There is also a show
command to show a table of roles and permissions per guard:
php artisan permission:show
When you use the built-in functions for manipulating roles and permissions, the cache is automatically reset for you, and relations are automatically reloaded for the current model record.
If you need to manually reset the cache for this package, you may use the following artisan command:
php artisan permission:cache-reset
Again, it is more efficient to use the API provided by this package, instead of manually clearing the cache.
For checking against a single permission using can
, you can use the built-in Laravel middleware provided by \Illuminate\Auth\Middleware\Authorize::class
like this:
Route::group(['middleware' => ['can:publish articles']], function () {
...
});
This package comes with RoleMiddleware
, PermissionMiddleware
and RoleOrPermissionMiddleware
middleware. You can add them inside your app/Http/Kernel.php
file.
protected $routeMiddleware = [
...
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];
Then you can protect your routes using middleware rules:
Route::group(['middleware' => ['role:super-admin']], function () {
...
});
Route::group(['middleware' => ['permission:publish articles']], function () {
...
});
Route::group(['middleware' => ['role:super-admin','permission:publish articles']], function () {
...
});
Route::group(['middleware' => ['role_or_permission:super-admin|edit articles']], function () {
...
});
Route::group(['middleware' => ['role_or_permission:publish articles']], function () {
...
});
Alternatively, you can separate multiple roles or permission with a | (pipe) character:
Route::group(['middleware' => ['role:super-admin|writer']], function () {
...
});
Route::group(['middleware' => ['permission:publish articles|edit articles']], function () {
...
});
Route::group(['middleware' => ['role_or_permission:super-admin|edit articles']], function () {
...
});
You can protect your controllers similarly, by setting desired middleware in the constructor:
public function __construct(){
$this->middleware(['role:super-admin','permission:publish articles|edit articles']);
}
public function __construct(){
$this->middleware(['role_or_permission:super-admin|edit articles']);
}
This package doesn't add any permission-specific Blade directives. Instead, use Laravel's native @can
directive to check if a user has a certain permission.
@can('edit articles')
...
@endcan
@if(auth()->user()->can('edit articles') && $some_other_condition)
...
@endif
You can use @can
, @cannot
, @canany
, and @guest
to test for permission-related access.
Additionally, if your reason for testing against Roles is for a Super-Admin, see the Defining A Super-Admin section of the docs.
If you actually need to test for Roles, this package offers some Blade directives to verify whether the currently logged in user has all or any of a given list of roles.
Optionally you can pass in the guard
that the check will be performed on as a second argument.
Check for a specific role:
@role('writer')
I am a writer!
@else
I am not a writer...
@endrole
is the same as
@hasrole('writer')
I am a writer!
@else
I am not a writer...
@endhasrole
Check for any role in a list:
@hasanyrole($collectionOfRoles)
I have one or more of these roles!
@else
I have none of these roles...
@endhasanyrole
// or
@hasanyrole('writer|admin')
I am either a writer or an admin or both!
@else
I have none of these roles...
@endhasanyrole
Check for all roles:
@hasallroles($collectionOfRoles)
I have all of these roles!
@else
I do not have all of these roles...
@endhasallroles
// or
@hasallroles('writer|admin')
I am both a writer and an admin!
@else
I do not have all of these roles...
@endhasallroles
Alternatively, @unlessrole
gives the reverse for checking a singular role, like this:
@unlessrole('does not have this role')
I do not have the role
@else
I do have the role
@endunlessrole
You can also determine if a user has exactly all of a given list of roles:
@hasexactroles('writer|admin')
I am both a writer and an admin and nothing else!
@else
I do not have all of these roles or have more other roles...
@endhasexactroles