When we’re building a web application, sometimes we need a concept when some users may have different permissions with another user to do something. For example, we can find it when building a forum where we have a regular user that, of course, has different privileges with the moderator, or even we can have an admin privilege that can do anything. So in this article, I’ll show you how to make a role-based authorization and its relationship between users and their roles/profiles. In my next article here, I’ll extend this explanation and implement it with Policy/Gate in front-end and back-end. Let’s start!
- Database Structure
- Database Migration
- Adjusting Models & Relations
- It’s Time to Try!
First thing first, let’s start by creating the database. As you know, there are several ways/structures on how we can store the relationship between users and their roles. But for this article, I’ll use the ER Diagram below to describe their relations. Don’t worry; it’s applicable when building a small/medium project.
Let me explain the diagram above. First, we have users where each of them can have more than one profile and its data stored in a pivot table named profile_user. You can see now, between users and profiles, they have many-to-many relationships so that we need a pivot table. Next, we have profiles with the same type of relationships with the permissions table.
Alright, let’s implement it by creating the migration now. We need four additional tables for profiles, permissions, and two pivot tables for profile_user and permission_profile.
php artisan make:migration create_profiles_table
php artisan make:migration create_permissions_table
php artisan make:migration create_profile_user_table
php artisan make:migration create_permission_profile_table
Again, if you think that my pivot table name is weird, I use the Laravel convention for naming them. It’ll make us easier later.
First, let’s set up the profiles table.
Nothing special here, move on to the next, permissions table.
Yeah, ok usual stuff. Next, permission_profile table.
In the permission_profile table, we have two foreign keys. They are referencing on permissions and profiles tables. Lastly, set up the profile_user table.
Alright, it’s done. Before running the migration, make sure you have set up your database name in your .env file.
php artisan migrate
After it succeeds, you should see five new tables in your database (at least).
Adjusting Models & Relations
The database is ready; now, it’s time for us to move into setting up the models and its relationships. So far, we only have the user model, so we need two more models. Let’s create them.
php artisan make:model Profile
php artisan make:model Permission
First, let’s configure the user model.
As you can see in the user model, we create three new functions at the bottom. The profiles() function returns its relationships with App\Profile. If you wonder why we are using the belongsToMany(), it because between users and profiles, they have a many-to-many relationship.
Then we have the assignProfile() function to assign the specified profile for a user. Actually, we can do this in the controller but, I think it’s cleaner if we do it in the model instead.
The last is permissions() function that returning an array of permissions from a specified user. Again, we do this in the model for better refactoring, but yeah, you can do it in the controller.
Let’s set up the profile model.
For the profile model, of course, we have permissions() function to return its many-to-many relationships with App\Permission. It also has users() function returning its relationships with App\User.
We have allowTo() function to add a new permission to the specified profile. We can have this logic in the controller or anywhere but, I’d rather keep it neat and straightforward, so I store it in the model.
Then we have to configure the permission model.
Hmmm yeah, it’s a very simple model indeed. We only have profiles() function to return its relationships with App\Profile.
After all those configurations, we’re ready to try it!
It’s Time to Try!
Wait, how can we try it if we don’t have any controllers or routes? This article only shows you how we can have role-based authorization with configuring the database and model so that it didn’t become a very very long article. If you’re wondering how we can implement this in real life project, or at least, know how to implement this authorization, take a look at my next article here to show you how we can use Policy/Gate and protecting our back-end & front-end. But for now, let’s try it using tinker.
Factory/Seeder is very useful when making some dummy data, but for now, I’ll keep using tinker to make it very clear of how it works.
php artisan tinker
Let’s say we want to have three new permissions; we can type this into our tinker:
$create_user = App\Permission::create(['name'=>'create_user']);
$update_user = App\Permission::create(['name'=>'update_user']);
$delete_user = App\Permission::create(['name'=>'delete_user']);
Then we might want two new profiles, so type:
$customer = App\Profile::create(['name'=>'customer']);
$service = App\Profile::create(['name'=>'service']);
Permissions and profiles are created now. Then we can configure to add some permissions to each profile.
Yeah, I know it’s a weird profile, but at least it simple. Next, we may need to create two new users:
$john = App\User::create(['name'=>'John','email'=>'email@example.com','password'=>'password']);
$jane = App\User::create(['name'=>'Jane','email'=>'firstname.lastname@example.org','password'=>'password']);
The last thing to do, let’s assign the profile to each user we have. Let’s say John is a customer, and Jane is a service.
Alright. Let’s take a look at what we created so far.
Interesting right? Now we have two users that each of them has its profiles and permissions.
So.. What now? Having this database structure and its relationships isn’t enough. In real life, we need this permissions to restrict users for doing something. In my next article here, I’ll show you how we can implement this using Policy, Gate, and Middleware.
I hope this article can be your good reference, and see you soon :)