Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

Permissions, Roles, Gates: Back-End

Premium
5 min read

Finally, in this course, we will take care of permission. In this lesson, we will take care of the back-end part. We will create Role and Permission models. Then we will add two roles: admin and editor. The admin role will be able to do everything and the editor will not be able to delete the posts.

network tab


First, we will create the models with migrations for roles and permissions.

php artisan make:model Role -m
php artisan make:model Permission -m

database/migrations/xxxx_create_roles_table.php:

public function up(): void
{
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}

app/Models/Role.php:

class Role extends Model
{
protected $fillable = ['name'];
}

database/migrations/xxxx_create_permissions_table.php:

public function up(): void
{
Schema::create('permissions', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}

app/Models/Permission.php:

class permissions extends Model
{
protected $fillable = ['name'];
}

Next, we need to create a pivot table for...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (29 h 14 min)

You also get:

54 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

Comments & Discussion

LA
Luis Antonio Parrado ✓ Link copied!

According to this tutorial we are defining the Gates but we are not using them in the controllers (or routes) to allow/prohibit the actions.

LA
Luis Antonio Parrado ✓ Link copied!

My solution in app/Http/Controllers/Api/PostController.php:

    // ...
		
    public function store(StorePostRequest $request)
    {
        $this->authorize('posts.create');

        // ...
    }
		
	//...
	
	public function update(Post $post, StorePostRequest $request)
    {
        $this->authorize('posts.update');

        // ...
    }

    public function destroy(Post $post)
    {
        $this->authorize('posts.delete');

        // ...
    }
		
	// ...
J
javi ✓ Link copied!

You are right. Database tables permissions, permission_role and role_user are correctly populated. But without these lines all users can delete posts.

LA
Luis Antonio Parrado ✓ Link copied!

foreach Closing bracket } is missing in app/Providers/AuthServiceProvider.php into boot method.

public function boot(): void
    {
        try {
            foreach (Permission::pluck('name') as $permission) {
                Gate::define($permission, function ($user) use ($permission) {
                    return $user->roles()->whereHas('permissions', function (Builder $q) use ($permission) {
                        $q->where('name', $permission);
                    })->exists();
                });
            } // **MISSING**
        } catch (QueryException $e) {
            //
        }
    }
DS
Dmytro Sakharuk ✓ Link copied!

As a respected ambassador of programming principles in general and KISS/YAGNI in particular, I must say that this is too complicated for this limited functionality :)

I would limit myself to the role column in the users table. Casting it to App\Enums\Role

namespace App\Enums;

enum Role: int
{
	case ADMINISTRATOR = 1;
	case EDITOR = 2;
}

And the policy App\Policies\PostPolicy

class PostPolicy
{
	// ...
	public function delete(User $user, Post $post): bool
	{
			return $user->role === Role::ADMINISTRATOR;
	}
	// ...
}
M
Modestas ✓ Link copied!

But that is a completely different approach from our example.

In your code, you are simply saying that user can have only one role, while in our example - we allow multiple roles. Then we are looking at your "KISS/YAGNI" example of a policy and it's hard-coded per role. What if our user has role Admin, but they are just learning and should not have ability to delete the user? I can't handle that case with your example.

Or to shorten what I just said - there are millions of ways to build the same thing. It just boils down to the project needs and future expansions

DS
Dmytro Sakharuk ✓ Link copied!

So, it all boils down to necessity. In this case, the functionality is excessive for CRUD operations for individual roles. The pinciples and approaches to software development advocate for keeping code simple and avoiding unnecessary functionality that is redundant.

M
Modestas ✓ Link copied!

In a way, you are right. This indeed goes deeper than it should. But one thing we learned over the years of building roles/permissions systems - they change rapidly. And preparing a system like this (or just installing spatie permissions package) is a great way to have the basics covered :) It is not that complex to understand and work with, yet provides you with a good base for future changes.