Simplifying authorization logic with Policies in Laravel

Laravel devs, here's a gem for you: πŸ’Ž Simplify your authorization logic with Policies. Manage permissions and access control in a clean, organized way! In this blog post, we'll explore how to use Laravel Policies to handle authorization logic and provide a real-life example to demonstrate their benefits.

Why Use Policies?

  • Separation of Concerns: Keeps authorization logic separate from your controllers and models.
  • Reusability: Define your authorization logic once and reuse it across your application.
  • Maintainability: Centralizes your authorization logic, making it easier to manage and update.

Step-by-Step Implementation

Let's walk through the process of setting up and using policies in a Laravel application.

Step 1: Creating the Policy

First, you need to create a policy for the model you want to authorize. In this example, we'll create a policy for the Post model.

php artisan make:policy PostPolicy

This command will create a policy file in the app/Policies directory.

Step 2: Defining the Policy Methods

Open the generated policy file and define the authorization methods. Each method corresponds to a specific action a user can perform on the model.

// app/Policies/PostPolicy.php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any posts.
     */
    public function viewAny(User $user)
    {
        return $user->is_admin;
    }

    /**
     * Determine whether the user can view the post.
     */
    public function view(User $user, Post $post)
    {
        return $user->id === $post->user_id || $user->is_admin;
    }

    /**
     * Determine whether the user can create posts.
     */
    public function create(User $user)
    {
        return $user->is_admin || $user->is_writer;
    }

    /**
     * Determine whether the user can update the post.
     */
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }

    /**
     * Determine whether the user can delete the post.
     */
    public function delete(User $user, Post $post)
    {
        return $user->id === $post->user_id && $user->is_admin;
    }
}

Step 3: Registering the Policy

Next, you need to register the policy in the AuthServiceProvider.

// app/Providers/AuthServiceProvider.php

namespace App\Providers;

use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    public function boot()
    {
        $this->registerPolicies();
    }
}

Step 4: Using Policies in Controllers

Finally, you can use the policy methods in your controllers to authorize actions.

// app/Http/Controllers/PostController.php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class PostController extends Controller
{
    public function index()
    {
        $this->authorize('viewAny', Post::class);

        $posts = Post::all();

        return view('posts.index', ['posts' => $posts]);
    }

    public function show(Post $post)
    {
        $this->authorize('view', $post);

        return view('posts.show', ['post' => $post]);
    }

    public function create()
    {
        $this->authorize('create', Post::class);

        return view('posts.create');
    }

    public function store(Request $request)
    {
        $this->authorize('create', Post::class);

        $post = Post::create($request->all());

        return redirect()->route('posts.show', $post);
    }

    public function edit(Post $post)
    {
        $this->authorize('update', $post);

        return view('posts.edit', ['post' => $post]);
    }

    public function update(Request $request, Post $post)
    {
        $this->authorize('update', $post);

        $post->update($request->all());

        return redirect()->route('posts.show', $post);
    }

    public function destroy(Post $post)
    {
        $this->authorize('delete', $post);

        $post->delete();

        return redirect()->route('posts.index');
    }
}

Example: Managing Post Permissions

In a real-life scenario, you might have different types of users (e.g., admins, writers, readers) with varying permissions for managing posts. Using policies, you can define these permissions in a centralized location and enforce them consistently across your application.

Creating Dummy Data

Let's generate some dummy data to work with.

php artisan tinker

// Inside Tinker
User::factory()->create(['name' => 'Admin', 'is_admin' => true]);
User::factory()->create(['name' => 'Writer', 'is_writer' => true]);
Post::factory()->count(5)->create(['user_id' => 1]); // Posts by Admin
Post::factory()->count(5)->create(['user_id' => 2]); // Posts by Writer

This command will generate dummy users and posts with different roles.

Viewing the Posts

Access the /posts route in your browser to see the list of posts.

Conclusion

Using policies in Laravel allows you to manage permissions and access control in a clean, organized way. By following the steps outlined in this blog post, you can leverage the power of policies to enforce authorization logic consistently across your Laravel applications.

Found this helpful?

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe