Add role and permission on your Laravel project 🔐
Tags: laravel, php, webdev, tutorial
Published: 2023-04-04 18:39:10

# Introduction
Authorization is a critical aspect of any application, as it ensures that users only have access to the resources they are allowed to see or modify. Laravel provides built-in features to make it easier to implement authorization in your application. In this post, we will learn how to implement authorization in Laravel without using any external libraries.

# Why is Authorization important and how Laravel helps with that
Authorization is important for security reasons, as it ensures that users only have access to the parts of the application they are authorized to use. Laravel makes it easy to implement authorization through its built-in middleware, which can be used to protect routes and actions.

# Creating the models
To keep this post from being too long, let's assume we've already created the migrations. If not, you can see the fillable property on the models and assume the table shape.
To implement authorization in Laravel without using external libraries, we need to create our own models for permissions, roles, and users. We can create the following models:

### Permissions model
This model only contains the relationship with the roles. Here is a small description of the fields:
- **name:** The permission name -> post.create
- **display_name:** A formated name to show on your UI if is required -> Create Posts.
- **description:** A brief description of the permission -> An User can create blog posts.

```php
class Permission extends Model {
    protected $fillable = [
        'name',
        'display_name',
        'description',
    ];

    // Relationship with roles.
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
}
```

### Role model
To create the relationship between the permissions and the roles, we need to create a pivot table called `permission_role` that has the `permission_id` and `role_id` fields.
Here we can see the relationship between the permissions and the users too.
The fields has the same meaning of the permissions table.

- **name:** The role name -> reviewer
- **display_name:** The formated name -> Post Reviewer
- **description:** A brief description -> An User that can review a post and approve it. 

```php
class Role extends Model {
    protected $fillable = [
        'name',
        'display_name',
        'description',
    ];

    // Relationship with permissions
    public function permissions()
    {
        return $this->belongsToMany(Permission::class);
    }
    
    // Relationship with users
    public function users()
    {
        return $this->hasMany(User::class);
    }
}
```

### User Model
Here we have the two escentials methods for our permissions system.
- **role():** Is our relationship with the Role model.
- **hasPermissionTo():** Here we receive as a parameter the permission name, and will return `true` if the user have the permissions, and `false` if don't have it.

```php
class User extends Authenticatable {
    protected $fillable = [
        'first_name',
        'last_name',
        'role_id',
        'password',
    ];

    // Relationship with role
    public function role()
    {
        return $this->belongsTo(Role::class);
    }
    
    // Check if the user have the permission
    public function hasPermissionTo($permissionName)
    {
        return $this->role->permissions->contains('name', $permissionName);
    }
}
```

# Where implement this?
Great, so we have our authorization logic, but now what?
There are a few different ways you can implement this authorization logic in your Laravel application. Most you can use two different approaches for this:

### Using Policies
```php
class PostPolicy
{
    /**
     * Determine if an user can create a post.
     */
    public function update(User $user): bool
    {
        return $user->hasPermissionTo('post.create')
    }
}
```
**Read more:** https://laravel.com/docs/10.x/authorization#creating-policies

### Using a Middleware
```php
class CreatePostMiddleware {
    public function handle(Request $request, Closure $next, $permission)
    {
        if (!auth()->user()->hasPermissionTo($permission)) {
            abort(403, 'Unauthorized action.');
        }
    
        return $next($request);
    }
}
```
**Read more:** https://laravel.com/docs/10.x/middleware#defining-middleware

# Summary
Implementing authorization without using external libraries is not difficult, and it gives you more control over how your application handles authorization. By creating your own models and relationships, and implementing the `hasPermissionTo` method, you can easily implement authorization in your Laravel application.

That's all, I hope it can be helpful for you 🥳