2.3 Setting Up Security
Our next step is to design our security system. In this lesson, we'll design our role system, seed the database, and build model relationships.
1.Introduction1 lesson, 01:23
2.Getting Started4 lessons, 45:12
3.Managing Pages6 lessons, 1:12:31
4.User Management2 lessons, 27:40
5.Managing the Blog3 lessons, 42:25
6.Adding Extras2 lessons, 25:48
7.Implementing the Front-End3 lessons, 32:10
8.Homework Review1 lesson, 07:11
9.Conclusion1 lesson, 01:24
2.3 Setting Up Security
In the previous session we started working with our database schemer. We created a pages table to store our content and now we just need to focus on the permission aspect. We want to be able to control what a user can and cannot do within our application. So we can approach this in a couple of different ways. The first way is to rely upon a third part package. And that is a viable solution. And in a real world scenario you might want to do that but it's also a good idea to understand how these types of systems are implemented at least at the basic level. So that if you do have to roll your own, you have an idea of where to start. So that's what we are going to do in this course. Starting in this lesson, we are going to create two tables for managing the permissions of a user. So, what we are going to essentially have is a three table system. Where we have our users, we have our roles, and then we have a table that's going to link the users and the roles together. So some people call this a LinkingTtable, and really that's the only term that I've heard used, but I'm sure that there are others. So we already have the users table that was created. Created in the previous lesson by Laravel itself. All we did was run the migration and we were good to go. So when it comes to the roles table, this is a very simple table where we just have an id and then we have the name of the role. We could also have a description if we wanted to go that far but we're just going to stick with the id and the name. So there's not going to be any other information here. It's just a table that contains the roles that our application is going to use. And then the linking table which we're going to call Role_User is going to have an id. It's going to have the role_id and then the user_id. So each record within this table is going to have the role and the user that that role is assigned to. And this is probably the most common way to approach a role-based permission system. So we just need to implement these things. Let's go to the command line, and we're going to start by using artisans scaffolding feature. Because the authentication aspect, the user registration and authentication is already built, all we need to do is just add that. So it makes sense to go ahead and do that, because eventually we're going to need this stuff. So we're going to say php artisan make auth:auth and it's simply going to say that the authentication scaffolding generated successfully. If you're curious as to what that did, if you go to app > Http > Controllers, we now have this Auth folder, and then the Controllers there. If you go to the resources > views, there's now this auth folder that has the views for our auth. So as far as creating users, logging them in, we don't have to worry about that, that's automatically done for us. And that is a huge relief, at least in my opinion. So now we just need to focus on creating those other two tables, our Roles and our Role_User. So the first thing is we need a model for our Role, because that is how we're going to access the roles within our system. So we're going to say php artisan make:model, we're gonna call it Role and we will let this create a migration for us. And then let's go ahead and create another migration since we're here at command line. And this will be for the Role_User table. So we will say php artisan make:migration and create_role_user_table. And we'll just hop on over to our code editor and we will make some changes here because we of course want to add our fields to those tables. So let's go to the migration folder, we now have two new migrations. Let's start with the Roles table. And we will add simply the name field here. So this is going to be h string, and that's pretty much it, as far as we're going to do. If you wanted to have a description and things like that then you can do that. But we're going to keep things simple. And as far as this particular migration is concerned we're done. So let's close that. Let's go to the create_role_table and this is also going to be very simple. We're going to add two new fields. One for the Role id, the other for the User id. So these are integer values and it would be role_id and we'll just copy and paste, make the change to user id there and that's it for that migration. And so now let's go to our models. Because there is a relationship between our user and the roles. So we are going to kinda do what we did in the previous lesson. Where in the User model, we created this page's method. We're going to do the same thing for roles, except that this isn't going to be a hasMany relationship. So, we will say public function roles and we will return this and we are going to say, belongsToMany and then we will specify App\Role. And then we will just create the inverse relationship. So let's just copy that, because that's all we really need to do except change the name of the method. So, inside of our Role class, we will then say, users belongs to many and then the model class is the user class. Now, later on we might want to add a few other methods to our user class So that we could check to see if a user is in a given role. Like for example let's just go ahead and [LAUGH] do that since we're here. Let's have a method called hasAnyRole, so that we can pass in an array of roles. And then we would just check to see if the user is in any of these roles. So we will return and we want to check our roles. So we will say this roles and we are going to use whereIn the name is in the roles that was passed. And we don't really care as long as we have something here. So if First returns an actual record then the user is in that role. But if it returns null, then the user is not in any of the provided roles and that is good enough for me. Let's just copy and paste that. And we will call this method hasRole, so that we pass in a single role. So that our query is going to be simply where, the name is equal to role, and we will do the same thing. If it returns a record, then that user is in the role, if not, then the user is not in that role. And that will give us an easy way to check if a user is in or isn't in a role. So now, let's just seed our database, because we have some tables already out there, well we haven't yet. We haven't migrated those yet, but let's go ahead and write some seeders. So let's go to our command line php artisan make: seeder and we're going to create one for the UsersTable. So we'll call this UsersTableSeeder. And we will do the same thing for our roles as well. This way we'll have some data to start with. And there we go. So lets go to our database folder inside of the seeds folder we now have the DatabaseSeeder which was there to begin with. But now we have the RollsTableSeeder and the UsersTableSeeder. So let's start with our rolls. Let's go ahead and use App\Roll so that we can use that roll class here because it makes it a whole lot easier. We first of all want to truncate, because whenever we seed our database we essentially want to start fresh. So we're going to truncate, which is going to take everything out of the roll table, if it exists, and then we want to create our rolls. So, we will say Roll::create, and let's just have a few roles, the simpler the better. Of course in a real application we might have a ton of roles. But for development purposes the more simple we have, the better we have. So let's have an admin, let's have an editor and let's have an author, and that's really all that we need. So now let's go to our UsersTableSeeder. And we are essentially going to do the same thing. We're going to seed the Users table with some users. But we're also going to attach some roles to those users. So let's use App\User. Let's also use App\Roll. And let's get two of our rolls, let's get the adminRoll which we will use Roll and then where name is gonna be equal to admin, and we'll get the first one there. And then let's also get just the author row. And we will get the one with the name author. So we have those two rows, let's create two users. The first one is going to be the admin. But of course, here we want to truncate the User table as well. So let's go ahead and call the truncate method. And then we will create our admin user. So we will say User::create, then we're going to pass in the data for this user. So, we'll say the name is going to be admin. The email address, it really doesn't matter, because we're not going to be doing anything with the email addresses. So let's say [LAUGH] email@example.com and then the password let's just make is password. But we want to encrypt this so we're going to say bcrypt ('password') so there is our admin user. Let's go ahead and copy this for our other user. Let's just call this User Joe. So we will have Joe, his name will be Joe, the email address will be firstname.lastname@example.org, and the password can be password as well. But then we need to attach our roles. So our admin is going to have the admin role, that just makes sense. So we're going to use our roles method. We are going to attach the adminRoll, and then for Joe we will use the author role. So we will attach authorRole. And then we just need to migrate our database and then run the seeder. Although we do need to go to our DatabaseSeeder, because we need to specify that we have some seeder classes here. Now we have the UsersTableSeeder already here but we want to run multiple seeders. We want to run not only the User but as well as the RolesTableSeeder as well. So we are going to pass in an array. The first one needs to be our rolls, because if you'll remember, whenever we seed our Users_Table, we are using data from the rolls table. So we need to seed rolls first. So we will say Roll::class and then UsersTableSeeder::class, although we need this table seeder. And then we can migrate and run the seeders. So let's go to the command line, php artisan migrate, and everything migrated. If it had an error, of course there would be an error here. But we did everything correctly, [LAUGH] so we're good to go there. And then we're going to say php artisan db:seed. And that's going to seed, although we have an issue, RollTableSeeder does not exist. And that is because that should be RollsTableSeeder. So let's run the seed again. And it helps if you spell role correctly and I probably didn't. Yep, there we go. [LAUGH] So if I do one thing wrong, once I typically know that I have done it wrong multiple times. So yeah, I'm sure you are screaming at the screen saying, you idiots and yes I am. So let's run the seeder again, there we go. Let's look at the data now. So we can go to our tables, let's refresh, we now have the roles. Let's look at them. We have our three roles, admin, editor, author. If we look at the users, we will see our two users. We have our admin and Joe. And then we look at the Role_User and we will have the records there. So our first record has a role_id of 1, that's the admin, and then the user_id of 1, that's the admin_user. Then we have the second record, the role_id that is the author role, and then the user_id which is 2, which is Joe_user. So we have set up our database for permissions. We implemented a three-table solution. One for the users, one for the role and then a linking table to link those two together. And we also added some methods to our User Class so that we can easily check if a user is in a given role.