Why Authorization Matters0:01
I think Uncle Ben got it right when he said that with great power comes great responsibility. Now we have just created an action that will give people money off inside our library. And that is a lot of power. We don't want anybody being able to administer that action. On that same note, we don't want anybody being able to see all data in our administration panel. For example, here in our app I have two new helpers, Rob Banks and Nick McCustomers. They're cheap labor, they're good behind the librarian desk, but I don't really trust them. I don't want them being able to just hand discounts out to anybody. So how does Nova allow me to limit actions and data based upon the user that's looking at the admin panel? Let me show you. I actually really like the way that Nova handles authorization,
Restricting Resources via Policies0:49
Let me show you. I actually really like the way that Nova handles authorization, because for the most part it's going to fall back to your standard Laravel policies for models. So here we have a CustomerPolicy tied to the Customer model. We have viewAny, view, create, update, and delete methods. Let's go ahead and alter the logic on the view method so that only Luke at laracast.com can view customers. Now here on the left I'm logged in as myself. Here on the right I'm logged in as Rob. And note that I can still click to access Thomas, but if I click on the right hand side nothing happens. There's no eye icon to view this example.
And note that I can still click to access Thomas, but if I click on the right hand side nothing happens. There's no eye icon to view this example. If I were to manually navigate to customer 70 I would be met with a 403. Let's update the create method with the same logic. Now for myself I can click this create button. I'm taken straight to the create customer form, but Rob isn't allowed to do that. He has no access to the create button because of our policy create method. Let's implement the same logic for the update and delete methods. Once again note that I have access to edit and delete a customer, but Rob does not have that access. Those icons are not available to him.
Once again note that I have access to edit and delete a Customer, but Rob does not have that access. Those icons are not available to him. If he tried to take those actions he would be met with a 403. There is one more action that we both have which is replicate in order to replicate a model. Inside the policy I have a replicate method, and once more I could return the same logic from here to only allow myself to replicate customers. If I select the more menu on my side, sure enough I can replicate, but there is no more menu on Rob's side. He cannot take any action anymore. All he can do is see the customer list.
Blocking Resource Index Access2:29
He cannot take any action anymore. All he can do is see the customer list. We can go one step further if we don't even want this to be visible to certain users. Let's implement that very same logic in the viewAny method. Nothing has changed for me, but if I try to refresh the customer index for Rob, he is not allowed access. He meets a 403. He can't even see the index page for customers. It's very simple really to manage access to your resources using standard Laravel policies, but what about actions?
Action Authorization Overview2:54
It's very simple really to manage access to your resources using standard Laravel policies, but what about actions? First of all let's reset the slate. All of these methods can return true again, and that should mean that Rob once again has access to see the customers. Currently he's also able to run the sendCustomerDiscount action. Now actions actually have a cascading set of authorization. We're going to start right at the bottom, and then we'll work up to the most specific ways of authorizing an action. The lowest level of authorization is the update method on a policy.
and then we'll work up to the most specific ways of authorizing an action. The lowest level of authorization is the update method on a policy. If you've not declared anything more specific, if this returns false, then inside the admin panel when you select a User, you can see the action, you can choose to send the discount, but when you run it, it will say you're not actually authorized. You're not allowed to do that. If your action is a destructive one, it will instead check for the delete method. Now what if you want to be a little more specific? In other words, what if you want them to be able to edit a Customer,
Policy-Based Action Controls3:53
Now what if you want to be a little more specific? In other words, what if you want them to be able to edit a Customer, but they still shouldn't be able to run that action? Well, again, still inside the policy, we can define a public function called runAction. It will receive three arguments, the user, the customer, and the action that is going to be executed. Now in this case, let's use our standard logic that only Luke can run this action. If we jump back into the admin panel, I'll select Thomas again. I'll go to send the customer discount and run,
If we jump back into the admin panel, I'll select Thomas again. I'll go to send the customer discount and run, and I'm not allowed because I'm not logged in as Luke. However, I can still edit Thomas. So now because update is returning true, I can edit, I can change details about Thomas. I'm just not allowed to run this action. Again, if you're working with destructive actions, then you can implement a method called runDestructiveAction, and this will be called instead of runAction.
Resource-Level canRun Authorization4:41
then you can implement a method called runDestructiveAction, and this will be called instead of runAction. Let's return this to true, and I'm going to show you the most specific way of authorizing an action. Let's jump into the Customer Nova resource where we actually declare the use of this action, and we can chain onto the instantiation of sendCustomerDiscount a canRun method. It accepts a closure. The closure is given the current request and the model that you're currently working with.
The closure is given the current request and the model that you're currently working with. In this case, it will be a customer, and you just have to return a Boolean as before. So let's return our standard logic, request user email is equal to Luke at laracasts.com. So only Luke should be able to run this action. Remember, all lower levels of authorization are returning true. So this is the only thing in authorization that will now return false. Let's see if it works.
So this is the only thing in authorization that will now return false. Let's see if it works. I'll refresh the index. We'll select Thomas again. Note now I don't even see the dropdown. There's no way that I can access this. Let's make this a little more lax by checking the customerID. So rather than checking for luke@laracasts.com, I'll say customerID is equal to 70. Now if we select customer 70, I can select the action from the dropdown.
I'll say $customerId is equal to 70. Now if we select customer 70, I can select the action from the dropdown. But if I select customer 69, that is not available to me. So as you're building your admin panel, do take that time just to decide who has access to various parts, who can execute actions. And no, you're probably not going to hard code the email as we've done in this episode. It would make a lot more sense to use gates and permissions for that task. But you get the concept, how simple it is, thanks to the fact that Nova integrates very closely.
But you get the concept, how simple it is, thanks to the fact that Nova integrates very closely with the standard authorization features that Laravel ships with.
