Adding Admin Navigation Link0:06
All right, let's move on to authorization, and I'll show you this in two steps. So let's begin with an example. I'm gonna open my nav components and let's add a new link to a private area of the website, like the administrator section. All right, so here is the link for the mobile dropdown, and here's the link for the desktop view. If I come back and give it a refresh, here we go. But then if I zoom in, we also have a link here.
If I come back and give it a refresh, here we go. But then if I zoom in, we also have a link here. And of course right now, if I click on it, we get a 4 0 4 because we haven't registered a route. All right, let's do that now. So we're not actually going to build this, I just wanna demonstrate how we can protect a section of our site like this. So this will simply return a text, like a private admin only area. You get the idea, okay?
Defining Gates in Provider0:48
admin only area. You get the idea, okay? So if we come back and refresh, now currently anyone in the world can access this private administrator section. So let's fix that. So here's what we're gonna do. I'm gonna open up my sidebar and visit app providers, app service provider. So this is your first introduction to service providers. I think of them sort of like, uh,
So this is your first introduction to service providers. I think of them sort of like, uh, bootstrappers for the application. You can bootstrap any kind of component or package or feature with the framework. You can register things with the framework, uh, put things into its container. And then once the framework has booted, you can do anything that would make sense for the feature or the component or the package.
that would make sense for the feature or the component or the package. So in this case, I wanna register some authorization rules, and I'll do it right here. I will use the gate facade, and yet this is cool. Imagine an actual gate that's closed, and we will define a rule that effectively determines whether or not that gate can open up for the user. So let's define a rule and name it anything you want.
or not that gate can open up for the user. So let's define a rule and name it anything you want. You can be very generic. Can the the current user administer? And that would be fine if you wanna be a little more direct, like can you view the admin section? Maybe people on your staff can view the admin section, but they can't, um, edit. So in those cases, you might wanna split that up into two different rules.
So in those cases, you might wanna split that up into two different rules. So let's just start with viewing. Can you even see that page? Alright, so this will receive the current user and this will return a Boolean that indicates whether or not the current user, uh, has this particular permission. Alright? So at least to start, I'm just gonna return true here. If you're signed in, you automatically have permission
Using Blade Can Directive2:25
I'm just gonna return true here. If you're signed in, you automatically have permission and then we'll tweak that in just a second. Alright, so we have a authorization rule and now I want to use that authorization rule. So here's what I'll do. I'm gonna visit my nav section once again and we're gonna wrap this within a new directive called can we use the can and cannot directives to handle authorization just like this.
and cannot directives to handle authorization just like this. If the user can view the admin section, then display this link and then I'll copy that and duplicate it down here as well. It's nice and readable and all you need to know is can, is just kind of a, once again a bit of sugar. It's a wrapper around an IF check. It's gonna check the authorization, specifically this rule,
It's a wrapper around an IF check. It's gonna check the authorization, specifically this rule, it'll run that closure, uh, pass the current user and that will determine whether or not we render this, uh, HTML. However, if I come back to my browser and let's switch back, give it a refresh, we'll zoom out a few clicks. There we go. Notice I don't see it at all, even though let's go back even though we returned true.
There we go. Notice I don't see it at all, even though let's go back even though we returned true. So yeah, this is, this is a common trap. Um, or or at least a quirk that you may run into. You'll define a rule, you'll hard code true, you will test it out and it doesn't work. Alright? So here's a a key thing you need to understand. Laravel will by default require an authenticated user. And if you are not authenticated, it doesn't even bother here.
And if you are not authenticated, it doesn't even bother here. Uh, it doesn't even bother running this closure, it instantly returns false, okay? But sometimes you will want a rule that does allow guest users. So you just have to determine, uh, what is appropriate. So in this case, if you think about it, do you need to be signed in to view the administrator section? Yes, that makes sense. So I would always expect an
to be signed in to view the administrator section? Yes, that makes sense. So I would always expect an authenticated user, but once again, in situations where that can be optional, here's what you can do. You can just, um, make it optional or you can do user equals no, right? I usually just do this though. Alright, so now, uh, you can, uh, give us a user if you have one, but if the user hasn't signed in,
give us a user if you have one, but if the user hasn't signed in, it's okay, this is optional. Alright? So now if I come back and give it a refresh, we are running that closure and we do return true, but yeah, nonetheless, in this case it would make sense. At the very least, you need to be signed in in order to run this authorization check. Alright, so back to the browser refresh. Let's log in.
run this authorization check. Alright, so back to the browser refresh. Let's log in. All right, we're signed in as John, and sure enough, because we return true for everybody, he, and once again, every signed in user can see that section. All right, so let's add some more constraints. Let's switch back and yeah, again, this just depends on what your application looks like and what the scale of your app is. And my advice for you is,
and what the scale of your app is. And my advice for you is, is don't make it more complex than it needs to be. If you're building a small little site or, or let's say you're building almost like a, a static site, uh, your blog and you just have this one section where only you can create posts or, uh, view certain private things. In that case, again, maybe your ID is one, that's fine. The user with an ID of one is, is the administrator.
In that case, again, maybe your ID is one, that's fine. The user with an ID of one is, is the administrator. We know that it's no problem. So if we come back, I believe John, who we are signed in as is, uh, does have an idea of one so he can access it, but maybe the the admin is two, then if we switch back, and of course John is not going to see that link. So yes, it's, it's a little blurry. Like it requires some, some knowledge on the developer's part that the user
Like it requires some, some knowledge on the developer's part that the user with a 90 of one is always administrator. But again, for, for a small app, it's fine. Trust me, it's fine. Uh, another option though is, is maybe you update your user's table and then you add something very simple like role or type. What is the role of this user? Uh, are they, are they just a simple member or are they,
What is the role of this user? Uh, are they, are they just a simple member or are they, or are they an admin member or admin? And then yeah, your administrator, uh, will have this role set to admin and then we can check that field to determine whether or not they have access. Again, that's entirely fine as well, and that will take you a long way. Uh, it's only at the point when you have maybe endless users
and that will take you a long way. Uh, it's only at the point when you have maybe endless users and lots of people on your team where you might wanna reach for a more role-based, uh, authorization system, but we don't need to do that right now. Okay? So, uh, by the way, if we took that other approach, we might say determine whether or not the user's role is an admin or remember user is an instance of this class and you can add any helper method you want, right?
or remember user is an instance of this class and you can add any helper method you want, right? So you could say right up here, method is admin, and then once again, just check if the role is admin, uh, assuming we had that field. All right, well now you would simply say return user is admin and that would work as well. All right? So you have a lot of flexibility here. That's my point. And then again, to reiterate, don't feel like you need to make something super complex.
That's my point. And then again, to reiterate, don't feel like you need to make something super complex. You probably don't. Um, and if you, if if you're not sure, then tilt towards simplicity and then you can always build something more complex later. Okay, anyways, let's bring this back to checking and if your ID equals one. Alright, so this is really cool. We've now learned that we can define a gate
Alright, so this is really cool. We've now learned that we can define a gate or an authorization rule within our app service provider. And it's a simple closure based system, very similar to how you might define a route that uses a closure to handle the response. Next, we've learned that within our components we can use the can directive and we can then reference that authorization rule to conditionally render, uh,
Protecting Routes with Can8:08
and we can then reference that authorization rule to conditionally render, uh, HTML blocks, which is very cool. Now, we can also use a can method on our routes themselves. So for example, right now we're just protecting the HTML that shows the link, but we're not actually protecting the, um, the endpoint in the round itself, which means if I switch back and I attempt to visit the admin section, well John Doe can access that,
and I attempt to visit the admin section, well John Doe can access that, but real quick, let's just return false. Nobody can access it. Well, at the moment I still see it because we're not actually protecting that route. So once again, we can do that in two ways. If I return to my routes file, I can apply it directly to the route. In the same way that we apply an off middleware
I can apply it directly to the route. In the same way that we apply an off middleware to the route, I can use the can method. Again, notice that matches up with the blade directive and once again I can say view admin. Alright, so now we have hooked up that gate, that authorization rule to this route and it's going to fire. So think about it, if the user visits the admin section, we're first gonna check, uh, with this middleware,
So think about it, if the user visits the admin section, we're first gonna check, uh, with this middleware, can the user view the admin section and it'll run this closure, it returns false and that means nope, you are unauthorized. So now if we come back and refresh, we get a 4 0 3 forbidden. Alright, perfect. Um, this is very good to know. And hmm, here's what I'll say if I switch back. Uh, developers kind of split on this.
And hmm, here's what I'll say if I switch back. Uh, developers kind of split on this. Some people really like to handle authorization at the route level and others feel like it's kind of hidden away and they would prefer to handle it, uh, directly within either their controller or the closure In this case. Again, there's no right or wrong. You just kind of pick what feels good to you.
Again, there's no right or wrong. You just kind of pick what feels good to you. If you're working on a team, just adopt whatever they are using. But I wouldn't say there's a right or wrong in this case. So I'm gonna show you both. Here is the middleware approach, but if I remove this, I could also handle it directly again within the closure. Or if I had a controller action, I could do it directly. Here. It's the exact same thing.
Authorizing Inside Route Closure10:16
Or if I had a controller action, I could do it directly. Here. It's the exact same thing. All right, so let's switch back and now how would I, excuse me, how would I perform that authorization check. I can do it like this. I can say gait authorize, and then I reference my gait, uh, authorization rule, and that's it. So if you're ever curious what we need to do here, just command, click and figure out what it's returning.
So if you're ever curious what we need to do here, just command, click and figure out what it's returning. Is this returning a Boolean? No, it returns a response, it calls authorized, and if it's denied, if you are not authorized, then an exception is thrown and that will bubble up and be converted into the proper response. So that means all I have to do is say gate authorize. All right, let's give that one a shot back to the browser, give it a refresh, and we still get a 4 0 3 forbidden.
All right, let's give that one a shot back to the browser, give it a refresh, and we still get a 4 0 3 forbidden. Perfect. Okay, now here's, here's one thing you might be aware of. If we return a 4 0 3, that's an indication that this URL and this endpoint is real. It does exist and often, uh, companies or developers may not want to share that information. For example, if you try to access slash admin on my site and you get a 4 0 3, well that means yep,
Returning 404 for Unauthorized11:24
For example, if you try to access slash admin on my site and you get a 4 0 3, well that means yep, there is an admin section, you're just not authorized to access it. So in these situations, sometimes people prefer to instead return a 4 0 4, uh, a not found status code rather than a 4 0 3. So yeah, if you wanna do that, of course you can configure these things. And here's how, let's go to our rule.
of course you can configure these things. And here's how, let's go to our rule. And by the way, if you're using PHP storm, you should be able to command click on the rule itself, and it it will take you to where it is defined. Okay? So here's what we can do. Rather than returning a Boolean, I'm going to return response and you wanna grab the right one. We want, um, not the facade, not illuminate HTTP response, but the, uh, auth access response.
We want, um, not the facade, not illuminate HTTP response, but the, uh, auth access response. Okay? So yeah, notice we have the option for allow, deny, deny is not found, which is 4 0 4 or deny with status. Okay? So here's what you could do. You could say, look, if the user id, uh, equals one, then they are allowed. So you could say return response, allow, otherwise return response, deny, uh, that will set 4 0 3, or we can deny with a custom status,
otherwise return response, deny, uh, that will set 4 0 3, or we can deny with a custom status, or once again, because this is so common, you can just say deny as not found, and that will instead return a 4 0 4, all right? Or you can combine these, use ary whatever you want. So if I come back, give it a refresh. Notice that 4 0 3 will switch to four. Oh, are we, oh yeah, John is, is authorized. Let's say, um, whoever is, is number two is authorized.
Oh, are we, oh yeah, John is, is authorized. Let's say, um, whoever is, is number two is authorized. Now John gets not a 4 0 3, but he gets a 4 0 4 not found. So you do have control over these things if that is important to you. Alright, very good to know. So here's what I would generally recommend doing. If you're building kind of a smallish project, something kind of medium, maybe you're the only person working on it,
something kind of medium, maybe you're the only person working on it, I might simply say, well, uh, look, return. If the user is an administrator, then I would create a method for that. If that's the case, uh, I probably don't even care about the status code. I'm just gonna return the boole in itself. Whatever is returned here, uh, if I did care about the status, then in that case I would do
Whatever is returned here, uh, if I did care about the status, then in that case I would do response allow or response, deny or deny, uh, as not found. Um, and this is generally what I would do. Alright, so now on user, once again, like we learned, we can add what is effectively a getter or, or a little helper method is admin that's going to return a Boolean. And then whatever logic you want to use for your application
to return a Boolean. And then whatever logic you want to use for your application to determine if this user, um, is considered an administrator. And yet that might just be check if the role is admin and that that's good enough. You have a basic field that determines where you exist in this application, and that's good enough for a very long time. Um, that would be fine
and that's good enough for a very long time. Um, that would be fine and that's what I would recommend to you at this stage in your learning. So once again, um, role does not exist. So we will set it to one only. John is an admin and we're good to go here. John can access the administrator area. John can view, um, any links to the administrator area, but nobody else can see that.
John can view, um, any links to the administrator area, but nobody else can see that. Let's sign in as Jane. All right, here are Jane's ideas, but notice nope, no link to the administrator section and that's exactly what we want. Alright, so I wanna talk about authorization just a little bit more in the next episode where we will discuss policies.
