در حال بارگذاری ...

Admin Column Limitations0:00

In the previous episode, we started looking at user authorization by the most simple means possible, and that was adding an admin column to the user table. It can't get any simpler than that, and there is something to say about simplicity, because, well, it's simple, it's easy to understand, and for the most part, it's easy to use. Say, for example, we used that isAdmin column inside of our navigation view. We are showing or hiding the user's link in our dashboard based upon if the user is an admin, and that's a perfect use of that column. We can use it inside of our Blade views, we can use it inside of our controllers, inside of our services, we can use it anywhere, but it does leave some to be desired. Because while, yes, we can use it inside of our controller, our code starts to look like this.

Defining an Authorization Gate0:48

we can use it anywhere, but it does leave some to be desired. Because while, yes, we can use it inside of our controller, our code starts to look like this. If a User is not admin, then they are unauthorized, and we would need to do that for all of the other methods here. And that's not feasible, it's certainly not maintainable. So instead, what we can do is tap into Laravel's user authorization system by using a gate. A gate is Laravel's most simple user authorization feature. It allows us to essentially define an ability and then determine if the user is able to perform that ability. But it also works as middleware, which is something that we will see here in a moment. Let's first of all create a gate. So I am inside of the app/Providers/AppServiceProvider.php, inside of the register method,

Let's first of all create a gate. So I am inside of the AppServiceProvider, inside of the register method, and we will use the Gate facade to define an ability. We'll just call it adminAccess. And then the second argument that we pass to this define method is a closure that gives us the $user object. So here we can return if the $user is an admin. Now, at first glance, this might seem like, what have we gained? Because now we are writing a lot of extra code in order to make this work. But now we are hooking into Laravel's authorization system, which means that, you know, once again, anywhere within our application,

Using Gates in Views2:11

But now we are hooking into Laravel's authorization system, which means that, you know, once again, anywhere within our application, be it inside of a view, inside of a controller, inside of a service, inside of our routes file, we can determine if a User can have admin access. Which means we can go back to the navigation view. And while, yes, this is readable, if the User is admin, then show this link, we can change this by using the can directive. Can the User have admin access? Then, perfect, we will display this link. Otherwise, it is hidden from them.

Then, perfect, we will display this link. Otherwise, it is hidden from them. And whenever we view this in the browser for an admin, we can see, yes, that user's link is certainly displayed. But for a user who is not an admin, well, we still see the unauthorized message. So let's change that. Inside of our UserController, let's get rid of this check if the user is an admin. And we can see that, yes, the user's link is not displayed. But, of course, we need some kind of check because we don't want just any user to access the user list. But we can do this a little bit better.

Protecting Routes with Gate3:17

But, of course, we need some kind of check because we don't want just any User to access the user list. But we can do this a little bit better. We don't have to directly access the isAdmin column now because we have our Gate. And if we deny the ability of admin access, well, then we will return our unauthorized response. But even that isn't something that we want to do because then we would have to go to every method inside of every protected Controller and ensure that the User does not have that ability. So while this is easier to read, at least in my opinion, it's definitely not something that we want to actually implement because it would be so much better if we could do that whenever we define our routes. And we can because we can use our Gate as middleware.

because it would be so much better if we could do that whenever we define our routes. And we can because we can use our gate as middleware. If the User can have admin access, then they are going to be granted access to the user's resource. And so, once again, for our test User who is an admin, we can see that, yes, they can still access our user list. But for our normal User, they get this error that the action is unauthorized. And it doesn't matter what they try to access. If they try to access the edit page for the User with an ID of one, it is still unauthorized because we are protecting those routes with our gate. And the beautiful thing about gates is that we can use them to create other gates.

Gate with Resource Ownership4:39

because we are protecting those routes with our gate. And the beautiful thing about gates is that we can use them to create other gates. Like, for example, an Admin should be able to manage the articles. They should be able to edit and delete. But just a normal User should not be able to edit and delete really any article except the ones that they have created. Now, ideally, yes, the list here would just show the articles that the User created. But that doesn't help us as far as an example is concerned. But we can easily do this by just defining another gate. So back inside of our AppServiceProvider, let's define another gate.

But we can easily do this by just defining another gate. So back inside of our AppServiceProvider, let's define another gate. We'll call this manageArticle. And I guess we can make it plural. And the first thing we could do is return if the $user is allowed admin access. Because if the $user is an admin, of course, they can manage an article. But then we also need to check if the $user->id is the same as the $article->author_id. But, of course, we need an Article to do that. So let's add some type hints. Let's have the User type hinted.

So let's add some type hints. Let's have the User type hinted. And we can go ahead and do that for our other gate. But then for this manageArticles, we also want the Article that we are going to be working with. So that now inside of the index view for our articles, let's see, here are the links. So, once again, we can check if the User can manageArticles. Well, then we will display those links. Otherwise, they won't see anything at all. But, of course, we need to know what Article that we want to check for. So we can just pass that as another argument to the can directive.

But, of course, we need to know what Article that we want to check for. So we can just pass that as another argument to the can directive. And so, once again, we check for our Admin User. We can see that those links are available. But when we look at just the normal User, we see that they are hidden, except for the Article that they created. But, you know, we also want to ensure that a User can't save an Article. Like, for example, we could come in here. We could inspect this. We could change the URL that we are posting to.

Authorizing Form Requests6:45

We could inspect this. We could change the URL that we are posting to. So, really, for our edit requests, we need to protect that as well. So let's open up the ArticleUpdateRequest. And, you know, every request class has this authorize method, which, you know, the default is return false. But that really doesn't help us, because any request that comes in with this object is going to fail. So by returning true, of course, that allows us to edit an article. But we want something a little bit more involved.

So by returning true, of course, that allows us to edit an Article. But we want something a little bit more involved. We, once again, want to use our Gate. And if the User is allowed to manage articles, then we want to authorize that request. Otherwise, we don't. So this is going to do two things. This is going to ensure that admins can manage any Article, but it's also going to ensure that only users can manage their own articles. So we're getting two for one here, and I really like that.

but it's also going to ensure that only Users can manage their own articles. So we're getting two for one here, and I really like that. So, of course, let's just edit something here. We'll edit the title so that we know it was edited. We'll save, and we have too few arguments. And, yeah, that makes sense, because we didn't provide the article that we want to check if the User can manage that. So let's try this. We'll get the article.

So let's try this. We'll get the article. We will call route, and we want the article. That way we should be able to pass that here, and that should make our gate work. So if we go back and refresh, let's resubmit that form, and let's scroll on down. Hopefully that's, yes, that did, in fact, work. We can see that the title was edited. And if we tried to circumvent that check,

We can see that the title was edited. And if we tried to circumvent that check, let's do that by changing the URL for our form here. Let's set the ID to, I guess, let's 16. And if we edit our title, submit, we get the error saying that this action is unauthorized. And that is exactly the behavior that we wanted. So by using gates, we can now start to hook into, and I don't know if hook is the right word, but I'm going to use it.

and I don't know if hook is the right word, but I'm going to use it. We can hook into Laravel's built-in authorization system. It allows us to easily check if a User can do something throughout our application. Inside of our code, we just need to use the allows method on the Gate facade, pass in the ability that we want to check for, and any other supporting information that the Gate might need to make its decision.

and any other supporting information that the gate might need to make its decision. And inside of a view, we can use the can directive. By again, passing in the ability that we want to check and any supporting information. But we can also use it as middleware, just like we did inside of our routes/web.php file. We are protecting our User resource by ensuring that the User has admin access. And all we had to do was define a couple of gates.

by ensuring that the User has admin access. And all we had to do was define a couple of gates inside of the register method in our AppServiceProvider. It's amazing what just a few lines of code can help us achieve.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟