Laravel Policy - first try and problem solve
Basics
It is not uncommon to see code like this when related to user authorization. All the code was mixed in a single controller. Not only does this add complexity to the controller but also hard to maintain. The only advantage of this is to finish work earlier, but regret it in the future.
Therefore, Laravel introduces gate and policy. While the gate is rather a simple implementation to address the authorization problem, the Laravel policy makes authorization more complete.
Gate
The code above can be written using the gate. In the boot()
method of AuthServiceProvider
, the gate was defined in this way.
Gate::define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
It can be used in controllers like this
if (Gate::allows('update-post', $post)) {
// The current user can update the post...
}
However, this can be complex since all the gates were defined by the closure. It is necessary to use a more sophisticated way. Then the policy was introduced.
Policy
php artisan make:policy PostPolicy --model=Post
After generating the policy, we can define the access rules in App\Policies\PostPolicy
.
public function update(?User $user, Post $post)
{
return optional($user)->id === $post->user_id;
}
The policy can be used in the controller by controller methods or via the user model.
public function update(Request $request, Post $post)
{
// controller method
$this->authorize('update-post', $post)
// via user model
if (!$user->can('update', $post)) {
abort(403)
}
}
More usage can be seen in the Laravel documents.
Policy auto-discovery not working
The policy auto-discovery could not function well if the namespace structure was changed for models. The problem can be solved by adding a custom resolver in the boot()
method of AuthServiceProvider
.
Gate::guessPolicyNamesUsing(function ($modelClass) {
return 'App\\Policies\\' . class_basename($modelClass) . 'Policy';
});
Using guard other than the default one
authorizeForUser()
can be used in this scenario by specifying the guard to get the user.
$this->authorizeForUser($request->user('api'), 'update', $post);
References
[1]: Authorization - Laravel - The PHP Framework For Web Artisans
[3]: Laravel only allow owner user to access route - Stack Overflow