I’m working on a Laravel application right now and I got myself in a bit of a tangle about authorization policies because of an undocumented way of using them.
Overview of policies
In Laravel, Policies are a way of specifying who can take particular actions. In this application we are using resource controllers (with typical resource methods like index
, create
, store
, etc) and manually authorizing in the controllers using the controller helper method described in the documentation.
$this->authorize('create', Post::class);
or, for methods that require authorization for a particular object/model:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
}
The problem
The problem I had here is that in the latter example, it’s kinda unclear which policy is being used. In the first example above it’s explicit – we’re using using the PostPolicy
because we passed in Post::class
to specify which model we are using.
In the second example the Policy is not specified – I’m guessing that the class of the type-hinted Post
is used to determine which policy is called. But it’s not clear especially when…
The use case – and why the problem is a problem
In my case I’m authorizing users to edit users, so my controllers looked like:
public function update(Request $request, User $user)
{
$this->authorize('update', $user);
}
But then I wanted some child classes of the User
model, which look like:
class SuperAdmin extends User
{
protected $table = 'users';
}
Now, if a SuperAdmin is passed to the UserController, which Policy is used? And – I know I probably shouldn’t but – if I wanted to use a specific policy here, what do I do? My only option is to change the type hint, isn’t it? And I may not want to do that?
The solution!
Well, no. It’s not the only option. It turns out you can pass an array to the authorize
helper which seems to let you specify both the object you are trying to authorize for, and a specific class/policy:
$this->authorize('update', [SuperAdmin::class, $user]);
So yay! Now, there’s probably a whole bunch of reasons you wouldn’t/shouldn’t do this, but that’s not the point. I want to remember that you can choose a policy by specifying a class name. And…job done!