1 Installation
1.1 installing the package via composer:
composer require spatie/laravel-permission
1.2 Registering Service Provider
The service provider will automatically get registered. Or you may manually add the service provider in your config/app.php file:
'providers' => [
// ...
Spatie\Permission\PermissionServiceProvider::class,
];
1.3 Publish
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
Note : 2 files are created after running the above command
- config/permission.php
- database/migrations/2023_05_04_063758_create_permission_tables.php
1.4 Clear Config Cache
php artisan config:clear
1.5 Run migrations
php artisan migrate
Check created tables in Database
sqlite> SELECT name FROM sqlite_master WHERE type='table';
+------------------------+
| name |
+------------------------+
| migrations |
| sqlite_sequence |
| users |
| password_resets |
| failed_jobs |
| personal_access_tokens |
| permissions |
| roles |
| model_has_permissions |
| model_has_roles |
| role_has_permissions |
+------------------------+
11 rows in set (0.01 sec)
Note: Tables names are defined in config/permission.php
- roles
- permissions
- model_has_permissions
- model_has_roles
- role_has_permissions
2 Basic Usage
2.1 Update the User Model
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
use HasRoles;
2.2 Role and Permission Models
A Role and a Permission are regular Eloquent models. They require a name
Roles
Create user roles manually
use Spatie\Permission\Models\Role;
$admin_role = Role::create(['name' => 'admin']);
$guest_role = Role::create(['name' => 'guest']);
Check roles tables
sqlite> SELECT id,name FROM roles;
+----+-------+
| id | name |
+----+-------+
| 1 | admin |
| 2 | guest |
+----+-------+
Permissions
Create Permissions manually
use Spatie\Permission\Models\Permission;
Permission::create(['name' => 'create post']);
Permission::create(['name' => 'edit post']);
Permission::create(['name' => 'delete post']);
Permission::create(['name' => 'view post']);
sqlite> SELECT id,name FROM permissions;
+----+-------------+
| id | name |
+----+-------------+
| 1 | create post |
| 3 | delete post |
| 2 | edit post |
| 4 | view post |
+----+-------------+
2.3 Create a new users with Admin, guest role
use App\Models\User;
//Admin user
$user = User::create([
'name' => 'abhi',
'email' => 'abhi@test.com',
'password' => bcrypt('123456')
]);
//Admin Role - ID 1
$adminRoleId = 1;
$user->assignRole([$adminRoleId]);
//Guest User
$user = User::create([
'name' => 'benn',
'email' => 'benn@test.com',
'password' => bcrypt('123456')
]);
$roleId = 2; //Guest Role
$user->assignRole([$roleId]);
`
Get Roles
$user = User::find(1);
$roles = $user->getRoleNames(); // Returns a collection
dump($roles); exit();
#items: array:1 [▼
0 => "admin"
]
3 Check User Role
3.1 Snippet
Route::get('/create-post', function () {
$user = User::find(2);
if($user->hasRole('admin')){
return "CREAT POST";
}else{
return "INVALID";
}
});
Check multiple permissions
// or at least one role from an array of roles:
$user->hasRole(['editor', 'moderator']);
3.2 Role - Permissions
Created Permissions
sqlite> SELECT id,name FROM roles;
+----+-------+
| id | name |
+----+-------+
| 1 | admin |
| 2 | guest |
+----+-------+
sqlite> SELECT id,name FROM permissions;
+----+-------------+
| id | name |
+----+-------------+
| 1 | create post |
| 3 | delete post |
| 2 | edit post |
| 4 | view post |
+----+-------------+
3.3 Assign permissions to Roles
Assign view post to guest role
$role->givePermissionTo($permission);
$role = Role::find(2); //guest
$permission = Permission::find(4); //view post
// A permission can be assigned to a role using either of these methods:
$role->givePermissionTo($permission);
OR
$permission->assignRole($role);
sqlite> SELECT * FROM role_has_permissions;
+---------------+---------+
| permission_id | role_id |
+---------------+---------+
| 4 | 2 |
+---------------+---------+
Multiple permissions can be synced to a role using either of these methods
$role = Role::find(1); //admin
$permissions = Permission::whereIn('name',['create post','edit post'])->get();
$role->syncPermissions($permissions);
sqlite> SELECT * FROM role_has_permissions;
+---------------+---------+
| permission_id | role_id |
+---------------+---------+
| 4 | 2 |
| 1 | 1 |
| 2 | 1 |
+---------------+---------+
3 rows in set (0.00 sec)
3.4 Get User Roles and Permissions
$user = User::find(1);
$permissions = $user->getPermissionsViaRoles();
dump($permissions); exit();
4 Direct Permissions
4.1 Assing Permission to User
$user = User::find(2);
$user->givePermissionTo('create post');
$user->givePermissionTo(['create post', 'edit post']);
DB Check
sqlite> SELECT * FROM model_has_permissions;
+---------------+-----------------+----------+
| permission_id | model_type | model_id |
+---------------+-----------------+----------+
| 1 | App\Models\User | 2 |
| 2 | App\Models\User | 2 |
+---------------+-----------------+----------+
4.2 Listing All provided permissions
$user = Auth::user();
#$permissions = $user->getDirectPermissions();
$permissionNames = $user->getPermissionNames();
dump($permissionNames); exit();
Illuminate\Support\Collection {#346 ▼
#items: array:2 [▼
0 => "create post"
1 => "edit post"
]
5 Protecting Routes
5.1 Default Middle ware
For checking against a single permission (see Best Practices) using can, you can use the built-in Laravel middleware provided by \Illuminate\Auth\Middleware\Authorize::class like this:
Route::group(['middleware' => ['can:create post']], function () {
Route::get('/create-new-post', function () {
return "Success";
});
});
Route::group(['middleware' => ['can:delete post']], function () {
Route::get('/delete-post', function () {
return "Success";
});
});
Test
http://127.0.0.1:8000/create-new-post
Logged User ID : 2
Output : Success
http://127.0.0.1:8000/delete-post
Logged User ID : 2
Output : 403 THIS ACTION IS UNAUTHORIZED
5.2 Package Middleware
This package comes with RoleMiddleware, PermissionMiddleware and RoleOrPermissionMiddleware middleware. You can add them inside your app/Http/Kernel.php file.
// Laravel 9 uses $routeMiddleware = [
//protected $routeMiddleware = [
// Laravel 10+ uses $middlewareAliases = [
protected $middlewareAliases = [
// ...
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];
5.3 Middleware via Routes
Then you can protect your routes using middleware rules:
Route::group(['middleware' => ['role:admin']], function () {
//
});
Route::group(['middleware' => ['permission:create post']], function () {
//
});
Route::group(['middleware' => ['role:admin','permission:create post']], function () {
//
});
Route::group(['middleware' => ['role_or_permission:create post']], function () {
//
});
You can specify multiple roles or permissions with a | (pipe) character, which is treated as OR:
Route::group(['middleware' => ['role:admin|guest']], function () {
//
});
Route::group(['middleware' => ['permission:create post|edit post']], function () {
//
});
Route::group(['middleware' => ['role_or_permission:admin|edit post']], function () {
//
});
5.4 Middleware with Controllers
You can protect your controllers similarly, by setting desired middleware in the constructor:
public function __construct()
{
$this->middleware(['role:admin','permission:create post|edit post']);
}
public function __construct()
{
$this->middleware(['role_or_permission:admin|create post']);
}
6 Blade Directives
6.1 permission
@can directive to check if a user has a certain permission You can use @can, @cannot, @canany, and @guest to test for permission-related access
@can('create post')
//
@endcan
OR
@if(auth()->user()->can('create post') && $some_other_condition)
//
@endif
6.2 Roles
@role('admin')
Admin
@else
Guest
@endrole
@hasexactroles('admin|guest')
//
@else
//
@endhasexactroles