Working with Policies in Laravel

Published in Originals on Dec 26, 2023

As a project grows larger, it can sometimes become confusing to keep authorization logic in the controllers. A solution to this is to use Policies.
But even for small projects, this is very powerful, in fact, I try to use it everywhere, it makes my code clean and readable.

What are Policies?

Policies are classes that centralize authentication logic for a specific model, or any other resource in your application.
They group authorization rules and make them easy to maintain.
When working in a team it's also easier to understand the rules, because they are centralized in one place instead of being sprinkled over the entire project.

How to use them?

Implementing is quite easy and should be a no-brainer. Here are a few simple steps.
A small prerequisite before we start is to already have an Article model.

Creating a Policy & defining Policy methods

First of all, we need to create our Policy using Artisan.

php artisan make:policy ArticlePolicy

This command will generate a Class file for us in /app/Policies named ArticlePolicy.

In this ArticlePolicy Class we can define our very own methods that we can use elsewhere in our application. Classic examples are View, Update, and Delete, but we could even define things like AnalyticsView, which we'll use to view the article's analytics for example.
Every project may have a few or many reasons to define exotic Policies but do try to keep them simple and clear.

Every Policy method should return a boolean, which basically represents the truthiness of weither a user may perform the action he/she's about to perform.

An example of the update method:

public function update(User $user, Article $article)
{
    return $article->user_id === $user->id;
}

Register the Policy

We need to make sure our application knows about our Policy we just created.
Registering the class can be done in the AuthServiceProvider, this provider is located at /app/Providers.
In this class we can use the protected $policies property to map policies to models.

So in our case we need to make sure our application knows that the ArticlePolicy needs to be used for the Article model.

Here is an example of how that looks:

protected $policies = [
    Article::class => ArticlePolicy::class,
];

Using the Policy

Now that we've registered our Policy and prepared a method to check whether a user is authorized to perform an update on an Article, we can use this in our controller to authorize a user against this check.
We can use the authorize method for this within our controller, like so:

public function show(Request $request, Article $article)
{
    $this->authorize('update', $article);

    // The actions that need to be performed go here.
}

Blade Directives

Once we have our policies set up, we can also hide our buttons, links, ... That shouldn't be there when we don't have permission to perform an action. We can reuse our policies for this using the @can directive.

@can('update', $article)
    <a href="{{ route('article.edit', $article) }}">Edit article</a>
@endcan

I think this is pretty neat instead of writing complex if statements in your blade files to check if the current user may perform or see something or not.

Wrapping up

Using Policies your code will be clean, maintainable, readable, and secure.
The risk of forgetting to edit something somewhere concerning authorization is no longer there.

All authorization is managed in a centralized location of your application and improves the security of your web application.

I would strongly advise using policies even for smaller applications. You will benefit in the long run. Also when you reopen the project after months, or maybe years. 🙂

See ya!



#laravel, #policies, #security, #authorization