This package allows you to manage user permissions and roles in a database.
Once installed you can do stuff like this:
// Adding permissions to a user
$user->givePermissionTo('edit articles');
// Adding permissions via a role
$user->assignRole('writer');
$role->givePermissionTo('edit articles');
If you're using multiple guards we've got you covered as well. Every guard will have its own set of permissions and roles that can be assigned to the guard's users. Read about it in the using multiple guards section of the readme.
Because all permissions will be registered on Laravel's gate, you can test if a user has a permission with Laravel's default can
function:
$user->can('edit articles');
Spatie is webdesign agency in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.
You're free to use this package (it's MIT-licensed), but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.
Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium.
All received postcards are published on our website.
This package can be used in Laravel 5.4 or higher. If you are using an older version of Laravel, take a look at the v1 branch of this package.
You can install the package via composer:
composer require spatie/laravel-permission
Now add the service provider in config/app.php
file:
'providers' => [
// ...
Spatie\Permission\PermissionServiceProvider::class,
];
You can publish the migration with:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"
After the migration has been published you can create the role- and permission-tables by running the migrations:
php artisan migrate
You can publish the config file with:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"
This is the contents of the published config/permission.php
config file:
return [
'models' => [
/*
* When using the "HasRoles" trait from this package, we need to know which
* Eloquent model should be used to retrieve your permissions. Of course, it
* is often just the "Permission" model but you may use whatever you like.
*
* The model you want to use as a Permission model needs to implement the
* `Spatie\Permission\Contracts\Permission` contract.
*/
'permission' => Spatie\Permission\Models\Permission::class,
/*
* When using the "HasRoles" trait from this package, we need to know which
* Eloquent model should be used to retrieve your roles. Of course, it
* is often just the "Role" model but you may use whatever you like.
*
* The model you want to use as a Role model needs to implement the
* `Spatie\Permission\Contracts\Role` contract.
*/
'role' => Spatie\Permission\Models\Role::class,
],
'table_names' => [
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your roles. We have chosen a basic
* default value but you may easily change it to any table you like.
*/
'roles' => 'roles',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your permissions. We have chosen a basic
* default value but you may easily change it to any table you like.
*/
'permissions' => 'permissions',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your models permissions. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'model_has_permissions' => 'model_has_permissions',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your models roles. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'model_has_roles' => 'model_has_roles',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your roles permissions. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'role_has_permissions' => 'role_has_permissions',
],
/*
* By default all permissions will be cached for 24 hours unless a permission or
* role is updated. Then the cache will be flushed immediately.
*/
'cache_expiration_time' => 60 * 24,
/*
* By default we'll make an entry in the application log when the permissions
* could not be loaded. Normally this only occurs while installing the packages.
*
* If for some reason you want to disable that logging, set this value to false.
*/
'log_registration_exception' => true,
];
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;
// ...
}
- note that if you need to use
HasRoles
trait with another model ex.Page
you will also need to addprotected $guard_name = 'web';
as well to that model or you would get an erroruse Illuminate\Database\Eloquent\Model; use Spatie\Permission\Traits\HasRoles; class Page extends Model { use HasRoles; protected $guard_name = 'web'; // or whatever guard you want to use // ... }
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 have 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']);
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
adds Eloquent relationships to your models, which can be accessed directly or used as a base query:
$permissions = $user->permissions;
$roles = $user->roles->pluck('name'); // Returns a collection
The HasRoles
also adds a scope to your models to scope the query to certain roles:
$users = User::role('writer')->get(); // Only returns users with the role 'writer'
The scope can accept a string, a \Spatie\Permission\Models\Role
object or an \Illuminate\Support\Collection
object.
A permission can be given to any user with the HasRoles
trait:
$user->givePermissionTo('edit articles');
// You can also give multiple permission at once
$user->givePermissionTo('edit articles', 'delete articles');
// You may also pass an array
$user->givePermissionTo(['edit articles', 'delete articles']);
A permission can be revoked from a user:
$user->revokePermissionTo('edit articles');
Or revoke & add new permissions in one go:
$user->syncPermissions(['edit articles', 'delete articles']);
You can test if a user has a permission:
$user->hasPermissionTo('edit articles');
...or if a user has multiple permissions:
$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);
Saved permissions will be registered with the Illuminate\Auth\Access\Gate
class for the default guard. So you can
test if a user has a permission with Laravel's default can
function:
$user->can('edit articles');
A role can be assigned to any user with the HasRoles
trait:
$user->assignRole('writer');
// You can also assign multiple roles at once
$user->assignRole('writer', 'admin');
$user->assignRole(['writer', 'admin']);
A role can be removed from a user:
$user->removeRole('writer');
Roles can also be synced:
// All current roles will be removed from the user and replace by the array given
$user->syncRoles(['writer', 'admin']);
You can determine if a user has a certain role:
$user->hasRole('writer');
You can also determine if a user has any of a given list of roles:
$user->hasAnyRole(Role::all());
You can also determine if a user has all of a given list of roles:
$user->hasAllRoles(Role::all());
The assignRole
, hasRole
, hasAnyRole
, hasAllRoles
and removeRole
functions can accept a
string, a \Spatie\Permission\Models\Role
object or an \Illuminate\Support\Collection
object.
A permission can be given to a role:
$role->givePermissionTo('edit articles');
You can determine if a role has a certain permission:
$role->hasPermissionTo('edit articles');
A permission can be revoked from a role:
$role->revokePermissionTo('edit articles');
The givePermissionTo
and revokePermissionTo
functions can accept a
string or a Spatie\Permission\Models\Permission
object.
Saved permission and roles are also registered with the Illuminate\Auth\Access\Gate
class.
$user->can('edit articles');
All permissions of roles that user is assigned to are inherited to the user automatically. In addition to these permissions particular permission can be assigned to the user too. For instance:
$role->givePermissionTo('edit articles');
$user->assignRole('writer');
$user->givePermissionTo('delete articles');
In above example a role is given permission to edit articles and this role is assigned to a user. Now user can edit articles and additionally delete articles. The permission of 'delete articles' is his direct permission because it is assigned directly to him. When we call $user->hasDirectPermission('delete articles')
it returns true
and false
for $user->hasDirectPermission('edit articles')
.
This method is useful if one has a form for setting permissions for roles and users in his application and want to restrict to change inherited permissions of roles of user, i.e. allowing to change only direct permissions of user.
You can list all of theses permissions:
// Direct permissions
$user->getDirectPermissions() // Or $user->permissions;
// Permissions inherited from user's roles
$user->getPermissionsViaRoles();
// All permissions which apply on the user
$user->getAllPermissions();
All theses responses are collections of Spatie\Permission\Models\Permission
objects.
If we follow the previous example, the first response will be a collection with the 'delete article' permission, the second will be a collection with the 'edit article' permission and the third will contain both.
This package also adds 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.
@role('writer')
I'm a writer!
@else
I'm not a writer...
@endrole
@hasrole('writer')
I'm a writer!
@else
I'm not a writer...
@endhasrole
@hasanyrole(Role::all())
I have one or more of these roles!
@else
I have none of these roles...
@endhasanyrole
// or
@hasanyrole('writer|admin')
I have one or more of these roles!
@else
I have none of these roles...
@endhasanyrole
@hasallroles(Role::all())
I have all of these roles!
@else
I don't have all of these roles...
@endhasallroles
//or
@hasallroles('writer|admin')
I have all of these roles!
@else
I don't have all of these roles...
@endhasallroles
You can use Laravel's native @can
directive to check if a user has a certain permission.
When using the default Laravel auth configuration all of the above methods will work out of the box, no extra configuration required.
However when using multiple guards they will act like namespaces for your permissions and roles. Meaning every guard has its own set of permissions and roles that can be assigned to their user model.
By default the default guard (auth.default.guard
) will be used as the guard for new permissions and roles. When creating permissions and roles for specific guards you'll have to specify their guard_name
on the model:
// Create a superadmin role for the admin users
$role = Role::create(['guard_name' => 'admin', 'name' => 'superadmin']);
// Define a `create posts` permission for the admin users beloninging to the admin guard
$permission = Permission::create(['guard_name' => 'admin', 'name' => 'create posts']);
// Define a different `create posts` permission for the regular users belonging to the web guard
$permission = Permission::create(['guard_name' => 'web', 'name' => 'create posts']);
This is how you can check if a user has permission for a specific guard:
$permissionName = 'edit articles';
$guardName = 'api';
$user->hasPermissionTo($permissionName, $guardName);
You can use the same methods to assign permissions and roles to users as described above in using permissions and roles. Just make sure the guard_name
s on the permission or role match the guard of the user, otherwise a GuardDoesNotMatch
exception will be thrown.
You can use all of the blade directives listed in using blade directives by passing in the guard you wish to use as the second argument to the directive:
@role('super-admin', 'admin')
I'm a super-admin!
@else
I'm not a super-admin...
@endrole
This package comes with RoleMiddleware
and PermissionMiddleware
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,
];
Now you can protect your routes using the middleware you just set up:
Route::group(['middleware' => ['role:admin']], function () {
//
});
Route::group(['middleware' => ['permission:access_backend']], function () {
//
});
Route::group(['middleware' => ['role:admin','permission:access_backend']], function () {
//
});
You can create a role or permission from console with artisan commands.
php artisan permission:create-role writer
php artisan permission:create-permission edit-articles
When creating permissions and roles for specific guards you'll can to specify the guard names as a second argument:
php artisan permission:create-role writer web
php artisan permission:create-permission edit-articles web
Two notes about Database Seeding:
-
It is best to flush the
spatie.permission.cache
before seeding, to avoid cache conflict errors. This can be done from an Artisan command (see Troubleshooting: Cache section, later) or directly in a seeder class (see example below). -
Here's a sample seeder, which clears the cache, creates permissions, and then assigns permissions to roles:
use Illuminate\Database\Seeder; use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission; class RolesAndPermissionsSeeder extends Seeder { public function run() { // Reset cached roles and permissions app()['cache']->forget('spatie.permission.cache'); // create permissions Permission::create(['name' => 'edit posts']); Permission::create(['name' => 'delete posts']); Permission::create(['name' => 'delete users']); // create roles and assign existing permissions $role = Role::create(['name' => 'Author']); $role->givePermissionTo('edit posts'); $role->givePermissionTo('delete posts'); $role = Role::create(['name' => 'Manager']); $role->givePermissionTo('delete users'); } }
If you need to extend or replace the existing Role
or Permission
models you just need to
keep the following things in mind:
- Your
Role
model needs to implement theSpatie\Permission\Contracts\Role
contract - Your
Permission
model needs to implement theSpatie\Permission\Contracts\Permission
contract - You must publish the configuration with this command:
And update the
$ php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"
models.role
andmodels.permission
values
If you manipulate permission/role data directly in the database instead of calling the supplied methods, then you will not see the changes reflected in the application, because role and permission data is cached to speed up performance.
To manually reset the cache for this package, run:
php artisan cache:forget spatie.permission.cache
When you use the supplied methods, such as the following, the cache is automatically reset for you:
// see earlier in the README for how these methods work:
$user->assignRole('writer');
$user->removeRole('writer');
$role->givePermissionTo('edit articles');
$role->revokePermissionTo('edit articles');
The package doesn't come with any screens out of the box, you should build that yourself. To get started check out this extensive tutorial by Caleb Oki.
Please see CHANGELOG for more information what has changed recently.
composer test
Please see CONTRIBUTING for details.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
This package is heavily based on Jeffrey Way's awesome Laracasts lessons on permissions and roles. His original code can be found in this repo on GitHub.
Special thanks to Alex Vanderbist who greatly helped with v2
, and to Chris Brown for his longtime support helping us maintain the package.
Povilas Korop did an excellent job listing the alternatives in an article on Laravel News. In that same article he compares laravel-permission to Joseph Silber's Bouncer, which in our book is also an excellent package.
Spatie is webdesign agency in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.
The MIT License (MIT). Please see License File for more information.