Why Role-Based Access0:00
Using a single column to control user access can be useful, but really for only very, very, very small applications, because most of the time, if we need to control user access, it's because we have a lot of different kinds of users. Like, for example, we could say that our application has three kinds of users. We have an admin who can do everything, manage users, create articles, and edit articles. Then we could say we would have an author, which is someone who could only create articles. They can't publish them or edit them, they can just create them. And then we would have editors who are responsible for editing and publishing those articles. And we could implement that with adding more columns to the user table, but that's not really a good approach because, well, it doesn't scale very well. And especially with larger applications, then you end up with a ton of different columns for individual roles. And sometimes those roles will change, and it's just not a good approach. So instead, typically what we do is implement some kind of role-based system, in which case we would have our users table.
Designing Role Tables1:06
And sometimes those roles will change, and it's just not a good approach. So instead, typically what we do is implement some kind of role-based system, in which case we would have our users table. We, of course, still need that. But then we would have a table that defines our roles, and that's all that table does. It just has the names of the roles. And then we will have a third table, one that just kind of links the two things together. Some people call it a pivot table. Some call it a linking table, a connecting table. There's a lot of names for it. But basically, it just allows us to essentially create a many-to-many relationship between our users and our roles so that we can assign multiple roles to a given user.
Creating Roles Migrations1:41
There's a lot of names for it. But basically, it just allows us to essentially create a many-to-many relationship between our users and our roles so that we can assign multiple roles to a given user. So we're going to implement that because this is a very common approach when it comes to defining permissions and controlling access to different parts of our application. So we're going to make a model called Role, and we just need the migration. We don't need a factory. But then we need another migration, one that is going to create our role_user table. This is going to be our linking table, whatever terminology that you want to use. And since we're here, let's just go ahead and wipe the DB. I mean, yes, we could run migrations to get the database into the way that we need. But, you know, this is all test data anyway.
I mean, yes, we could run migrations to get the database into the way that we need. But, you know, this is all test data anyway. We might as well just wipe it and start over. All right, so with that in place, let's go to the create_role_migration because all we really need here is a column for the name. That's all that this is going to have, just the name of the role, nothing else. So with that in place, we're done with that. And then we can open up the create_role_user_table because this is also going to be very simple. It will simply have foreign keys to the user_table. We want that constrained. And I guess on delete, it can cascade.
We want that constrained. And I guess on delete, it can cascade. So then we need a foreign key for the role_id. So every record inside of this pivot table is going to have a user_id and a role_id. And that's how we assign roles to a given User. This gives us the ability to assign multiple roles to a User. And if our application was set up, we could create new roles on the fly. That's the beauty of this kind of implementation. In our dashboard, we could have a section to create new roles and then assign those roles to users. So our migrations are done.
In our dashboard, we could have a section to create new roles and then assign those roles to Users. So our migrations are done. Let's just go ahead and migrate our database. Oh, no, we're not done because we need to go to the create_users_table migration. And we need to get rid of this is_admin column because now we are going to assign the admin role to a User. So let's wipe the DB. Let's migrate. Okay, so there we go. And since we're on that thought, let's open up the UserFactory and let's open up the User model because we need to get rid of where we use the is_admin column.
Adding Model Relationships4:15
And since we're on that thought, let's open up the UserFactory and let's open up the User model because we need to get rid of where we use the isAdmin column. So that's inside of the fillable array. That's also down here where we cast isAdmin as Boolean. But then inside of the UserFactory, we also set isAdmin there. So let's get rid of that. And I think we're good to go as far as getting rid of the isAdmin. So inside of our User model, you know, we have this method for our articles relationship. But we need some way to get our roles. And since this is a many to many relationship, we're going to use belongsToMany.
But we need some way to get our roles. And since this is a many-to-many relationship, we're going to use belongsToMany. And we will simply return this belongsToMany role. And that's going to work just fine. But we also need a method to easily determine if a User has a given role. So here we will return where we will access our roles. And if it contains a role with the name of the given role, then great, we are in that role. So we're good there. Let's close that. Let's open up the Role model because we need to create the fillable array where we can add in the name.
Let's close that. Let's open up the Role model because we need to create the fillable array where we can add in the name. But then we also need the users method because at some point in time, we will probably need to get the users that are assigned to a given role. So this once again is a belongsToMany relationship to where we will simply return belongsToMany and our User model. And I think that's it. All we need to do now is change our database seeder so that we can work with some new data. And there's quite a bit of new things here. So I'm just going to paste this in. We'll get rid of all of the old code.
Seeding Users and Roles6:06
So I'm just going to paste this in. We'll get rid of all of the old code. And then let's just go over that. It's very simple. So the first thing I do is create three Role instances, one for the Admin, one for the Author, one for the Editor. Then we create our User instances. We have an Admin user who is assigned the Admin role. We have an Author user who is assigned the Author role. And then an Editor user who, you guess it, has the Editor role. But then we have an Author Editor.
And then an Editor user who, you guess it, has the Editor role. But then we have an AuthorEditor. And this user is assigned two roles because this starts to demonstrate one of the powerful features of this particular implementation. We can assign multiple roles to a given user. So this AuthorEditor is both an Author and an Editor. So then we create 10 articles for the Author and then 10 articles for the AuthorEditor. So we should be able to seed the database. Hopefully we won't get any errors, and we don't. But before we do anything else, let's look at the database structure. So we have our users table, and nothing is out of the ordinary.
But before we do anything else, let's look at the database structure. So we have our users table, and nothing is out of the ordinary. This is just a normal users table. Then we have our roles table, our admin, author, and our editor roles. But then we have the role_user table. This is our pivot table to where we have the user_id with an id of 1 is assigned the role_id of 1, which is the admin. The user with an id of 2 has the role_id of 2. 3 has 3. But then our user that is both an author and an editor has two roles assigned. So that's how this works.
Updating Gates for Roles7:39
But then our User that is both an author and an editor has two roles assigned. So that's how this works. We have two tables with two separate entities. Then we have that pivot table that links those entities together. But now we need to change our gates. Because our admin access gate was checking if the User has the is_admin column as true, which that's not going to be the case anymore. Instead, we want to call the hasRole method. But a User has admin access not only if they are an admin, but also if they are an author or an editor. So we need to change this. The User has the role of admin or the role of editor or the role of author.
So we need to change this. The User has the role of admin or the role of editor or the role of author. And this has been bugging me. I should have named this accessAdmin. Because a gate, well, a gate isn't a role. It isn't a permission. It's really defining an action. Can a User access the admin or can the User manage articles? So the name of the gate needs to be more along the lines of an actual action. So we'll have accessAdmin.
So the name of the gate needs to be more along the lines of an actual action. So we'll have access admin. But here manageArticles is going to be a little bit different. Because a User can access the admin, but they might not necessarily be able to manageArticles. So really, we need to include all of the roles that can manageArticles, in which case is all of them. However, we have something else here because we were checking if the userId is equal to the articleAuthorId. But now that we have an editor role, editors should be able to do really anything as far as editing is concerned. So I'm not quite sure what I want to do here. But for right now, I'm going to do this. If the user has the admin role or the editor role or if the user has the author role and the userId is the same as the authorId.
But for right now, I'm going to do this. If the User has the admin role or the editor role or if the User has the author role and the User ID is the same as the author ID. I'm not sure if I want authors to be able to edit their own. But this is definitely something that we will need to address. Because now that we have multiple roles, the more complicated it becomes to determine if a User has access to something. But let's check this. Let's sign in as admin. Let's make sure we can still at least access our dashboard. We can access the articles, but we don't see the link for managing our users, which I kind of expected. I knew that there was going to be some things that we would need to address. But let's check out the author and let's see what the article list looks like for the author.
I knew that there was going to be some things that we would need to address. But let's check out the author and let's see what the article list looks like for the author. We can, of course, edit our own articles, which is what we wanted, but we can't edit anything else. So that's going to be okay. So now that we have a role-based system, we need to change the rest of our application to take those roles into account. And it's going to be much more than just trying to change the gates that we have. Because, as we saw, there are some things that aren't working correctly. And we might not need to use gates at all. We might need to take a different approach and use different strategies. But we will look at those in the next episode.
We might need to take a different approach and use different strategies. But we will look at those in the next episode.
