Content Index
- Roles and permissions
- Installation
- Methods for assigning: Permissions to roles, roles to permissions and users, permissions and roles
- Roles to permissions and/or users
- Permissions to roles (or roles to permissions)
- Policies vs Spatie in Laravel (Roles and Permissions) when to use?
- Roles and Permissions Systems - Spatie
- What are Policies in Laravel
- Practical example
- Assign a role to a user.
- What are policies
- Integration between Spatie and Policies
- Summary
Spatie Laravel-Permission is an open-source package for managing user permissions based on roles used with Laravel; it is a package that is easy to use when implementing a structure as commonly handled in projects today as permissions and roles, which we will go into more detail in the next section.
In this section, we will learn in detail how to use this package in a Laravel project and, with this, be able to protect resources in a more scalable and modular way than simply indicating an enumerated type column for the role; remember that we previously saw how to employ Test Driven Development (TDD) in Laravel.
Roles and permissions
In typical systems where it is required to protect application resources, roles and permissions are usually used to manage controlled access to each of the resources; roles and permissions are a mechanism to control and restrict access to different parts of a web application.
Permissions are specific actions that a user can perform in the application, for example, "publish a new article" or "delete a comment." With Spatie laravel-permission, you can associate roles and permissions to users and verify if a user has access to a specific action in the application based on their roles and permissions.
Roles are a way to group permissions, for example, you could have an "administrator" role that has permissions for all actions in your application, while a "user" role would only have permissions for limited actions.
To understand what was mentioned through an example, in the context of a web application, roles can be, for example, "administrator", "editor" and "reader". Each role has a different set of permissions that determines what actions it can perform.
For posts in an administrator role:
- Create post.
- Update post.
- Delete post.
- Detail/List post.
For categories in an administrator role:
- Create category.
- Update category.
- Delete category.
- Detail/List category.
For posts in an editor role:
- Create post.
- Update post (only their own).
- Delete post (only their own).
- Detail/List post.
For categories in an editor role:
- Create category.
- Update category (only their own).
- Delete category (only their own).
- Detail/List category.
For posts in a reader role:
- Detail/List post.
For categories in a reader role:
- Detail/List category.
You can get more information at:
https://spatie.be/docs/laravel-permission/v5/introduction
https://laravel-news.com/laravel-gates-policies-guards-explained
Installation
The installation of this package is the typical process in which we execute a composer command indicating the package we want to install:
$ composer require spatie/laravel-permissionRegister the provider:
config/app.php
'providers' => [
***
Spatie\Permission\PermissionServiceProvider::class,
];Publish the migration and the configuration file config/permission.php to be able to customize it:
$ php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"Run the migration:
$ php artisan migrateAnd we will have an output like the following:
2023_04_16_125650_create_permission_tables ................... 796ms DONEWith the previous command, several tables are created, you can inspect the permissions migration (***_create_permission_tables) and you will see that it consists of several tables:
- roles
- permissions
- model_has_permissions
- model_has_roles
- role_has_permissions
Expert tip: "Remember that spatie/laravel-permission doesn't just create tables, it creates a polymorphic Many-to-Many relationship. If you ever need to check permissions manually, use $user->getAllPermissions() to see the total union of direct permissions and those inherited by roles."
To be able to use permissions from the user entity, we register the roles trait:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use *** HasRoles;
***
}Methods for assigning: Permissions to roles, roles to permissions and users, permissions and roles
In this section, we are going to learn how to assign permissions to each corresponding entity, which can be of 3 types:
- Assign permissions to roles; this is the most common case since, in the end, roles are nothing more than a grouping of permissions, that is, a role can have from zero to N permissions.
- Assign roles to users; a user can have from zero to N roles, which internally contain the permissions, and with this, control access to the application modules.
- Assign permissions to users; although it is not the ideal approach, we can also assign permissions directly to users.
Let's look at these cases in detail:
Roles to permissions and/or users
With a permission or user, we can manage roles in the following way:
- removeRole() Removes a role from the user/permission.
- assignRole() Assigns a role to the user/permission.
- syncRoles() To synchronize roles, you must provide an array with the roles:
- The role or roles that are not established as arguments of this function but are assigned to the user/permission will be removed.
- The role or roles that are established as arguments of this function and are assigned to the user/permission are kept, and those that were not assigned to the user/permission will be added.
Permissions to roles (or roles to permissions)
As we mentioned before, roles contain the permissions that define access for users; if we check the roles model:
vendor\spatie\laravel-permission\src\Models\Role.php
public function permissions(): BelongsToMany{}
And through the trait of:
Spatie\Permission\Traits\HasPermissions;
We will see that we have access to a series of methods equivalent to those presented above:
- revokePermissionTo()
- syncPermissions()
- givePermissionTo()
In a Policy, it looks like this:
// In your PostPolicy.php
public function update(User $user, Post $post) {
// 1. Spatie: Does it have the general permission?
if ($user->can('edit all posts')) return true;
// 2. Policy: Is it the original author?
return $user->id === $post->user_id;
}| Feature | Spatie Laravel-Permission | Laravel Policies (Native) |
|---|---|---|
| Focus | Global and reusable roles and permissions. | Model-specific business logic. |
| Complexity | Ideal for systems with many roles. | Ideal for rules based on ownership (e.g., post->user_id). |
| Storage | Data persisted in database. | Code based on classes and methods. |
| Reusability | Very high (dynamic assignment). | Low (logic coupled to a model). |
| Ideal for... | Admin panels, SaaS. | Resource authorization by owner/author. |
Policies vs Spatie in Laravel (Roles and Permissions) when to use?
I wanted to make a quick clarification on when to use Spatie and when to use policies in Laravel. I assume you already have basic knowledge of the subject, but I will explain it quickly.
Roles and Permissions Systems - Spatie
Spatie is a system that allows managing roles and permissions in a simple way. For example, you can assign one or more roles to a user, and each role can have specific permissions to perform certain actions within the application.
Practical example
Suppose we have a blog-type application with a basic CRUD (create, list, edit, delete). We can define roles such as:
- Editor: can edit articles and view lists, but not create or delete.
- Administrator: has access to all CRUD operations.
In practice, Spatie facilitates this logic in a reusable way:
$user->assignRole('admin');
$user->givePermissionTo('edit articles');
if ($user->can('edit articles')) {
// Access granted
}Here, basically, permissions translate into conditionals that control access to resources. The advantage is that you can easily reuse these permissions and assign them to both users and roles.
What are Policies in Laravel
Policies are a more homemade and personalized system that allows controlling access to resources based on the business logic of your application. They are ideal when you do not need a complex system of roles and permissions, such as the one offered by Spatie.
Practical example
In my application, I have a system of books and courses. Every time a user buys a book, a record is generated in the database:
$filePayment = FilePayment::where('user_id', $user->id)
->where('file_paymentable_id', $bookSection->book->id)
->where('file_paymentable_type', Book::class)
->first();
if ($filePayment == null)
return [202, "You have not purchased the book"];This is a good candidate for defining a policy, which would be responsible for validating if the user has access to the book's content. This way, repeating conditionals in multiple places of the application is avoided.
Policies are linked to business logic and models. While Spatie is more generic and oriented towards large systems, policies allow for finer control over specific resources and logical steps within the application.
Basically, everything translates into conditionals. The functions we see in Spatie act as intermediaries for a conditional, but in the background, we are always evaluating whether or not a user has a permission:
$user->assignRole('admin');
$user->givePermissionTo('edit articles');
if ($user->can('edit articles')) {
// Access granted
}With this, we have simple reuse of permissions: you can assign a permission to several users and verify it uniformly.
This system is very similar to what we find in Django, although in Laravel with Spatie it integrates easily with other components, such as policies. For example, you can:
Assign a role to a user.
Give permissions to that role automatically or independently.
In this way, Spatie takes care of managing permissions for you, and from there you only apply conditionals to verify if a user can perform an action, for example:
can('edit articles')You simply ask if the user has that permission, and that's it.
What are policies
Now, what is a policy?
Policies are similar to Spatie, but a bit more generic and focused on the business logic of your application. They are normally used when you don't need a complex system of roles and permissions.
In other words, while Spatie handles permissions and roles globally and reusably, policies allow you to define more specific rules directly linked to the models or resources of your application.
In the next practical example, we will see how to use policies to control access to certain resources without depending on a full roles and permissions system.
Integration between Spatie and Policies
In more complex applications, you can combine Spatie and policies:
- Spatie: defines general roles and permissions.
- Policies: implements specific rules based on business logic.
For example, you could have permissions to access books and, within a policy, validate that the user has actually purchased that book before allowing them to view the content.
Summary
- Spatie: generic roles and permissions system, useful for large applications and with many users and roles.
- Policies: more specific control linked to business logic and models, ideal for validating access to resources granularly.
In summary, policies focus on the internal logic of your application, while Spatie provides a general scheme of reusable permissions. Both can be combined according to the needs of your project.
The next step we will see is how to integrate CKEditor in Laravel.