Kritim Yantra
Mar 19, 2025
When building web applications, security is a top priority. One key aspect of security is authorization—deciding what users are allowed to do once they’re logged in. Laravel makes this task simple and elegant with two powerful tools: Gates and Policies. In this detailed blog post, we’ll explore how Gates and Policies work in Laravel 12, explain them in simple terms, and provide plenty of code examples to help you implement them in your projects. By the end, you’ll have a solid understanding of how to control user permissions like a pro!
Before we dive into Gates and Policies, let’s clarify what authorization means. Imagine you’re running a blog site. You have users who can log in—that’s authentication, which checks who they are. But not every user should be able to delete posts; maybe only the post’s author or an admin should have that power. That’s where authorization comes in—it decides what a user can do.
In Laravel, Gates and Policies help you set these rules easily. Whether it’s restricting access to an admin dashboard or limiting who can edit a post, these tools keep your app secure and organized.
Think of Gates as simple yes-or-no questions you can ask anywhere in your app. They’re like little guards that say, “Can this user do this action?” Gates are perfect for permissions that don’t depend on a specific object—for example, checking if someone can visit an admin page.
Gates are defined as small functions (closures) that return true
or false
. You set them up in one place and use them wherever needed.
Gates are usually defined in the AppServiceProvider
(located in app/Providers/AppServiceProvider.php
). For example:
<?php
use Illuminate\Support\Facades\Gate;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
// Define a Gate to check if a user is an admin
Gate::define('access-admin-panel', function ($user) {
return $user->is_admin; // Assuming 'is_admin' is a column in your users table
});
}
}
In this example, the Gate named access-admin-panel
checks if the logged-in user has the is_admin
flag set to true.
Once the Gate is defined, you can use it anywhere in your app. For example, in a controller:
<?php
public function showAdminPanel()
{
if (Gate::allows('access-admin-panel')) {
return view('admin.panel'); // Show the admin panel
} else {
abort(403, 'Sorry, you’re not allowed here!');
}
}
You can also use Gates in Blade templates with the @can
directive:
@can('access-admin-panel')
<a href="/admin">Go to Admin Panel</a>
@endcan
Gates can also accept additional parameters. For example, to check if a user can edit a specific post:
<?php
Gate::define('edit-post', function ($user, $post) {
return $user->id === $post->user_id;
});
Then in a controller:
<?php
public function editPost($postId)
{
$post = Post::findOrFail($postId);
if (Gate::allows('edit-post', $post)) {
return view('posts.edit', compact('post'));
} else {
abort(403);
}
}
Policies are classes that group authorization logic for a specific model. For example, a PostPolicy
might contain methods to determine whether a user can update or delete a post.
Policies are ideal for actions like “view,” “create,” “update,” or “delete” on a specific model.
Use Artisan to generate a policy for the Post
model:
php artisan make:policy PostPolicy --model=Post
This creates app/Policies/PostPolicy.php
, which might look like:
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
Laravel makes it easy to use policies. Policies help you decide if a user can do certain actions on a model (like a blog post or an order). There are two ways Laravel finds your policies:
Policies
(for example, app/Policies
), Laravel will automatically match your models with their policies. For example, if you have a User
model, the policy should be called UserPolicy
.
AppServiceProvider
.
Here’s an example of manually registering a policy for a Post
model:
<?php
use App\Models\Order;
use App\Policies\OrderPolicy;
use Illuminate\Support\Facades\Gate;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Gate::policy(Order::class, OrderPolicy::class);
}
}
In this code, we tell Laravel that whenever it checks permissions for a Post
, it should use the PostPolicy
class. This keeps your authorization logic organized and easy to manage.
If you need custom logic to guess the policy name, you can use Gate::guessPolicyNamesUsing
in your service provider’s boot
method. However, sticking to the standard naming convention is usually enough for most applications.
In a controller, you can use the authorize
method:
<?php
public function update(Request $request, Post $post)
{
if (!$request->user()->can('update', $post)) {
abort(403, 'Unauthorized');
}
$post->update($request->all());
return redirect('/posts');
}
In Blade templates, you can use the @can
directive:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Edit Post</a>
@endcan
Both Gates and Policies are used for authorization, but they differ in scope:
In practice, you might use Gates for general access rules and Policies for model-specific permissions.
<?php
Gate::define('manage-users', function ($user) {
return $user->hasRole('admin');
});
Use it like:
<?php
if (Gate::allows('manage-users')) {
echo "Welcome, admin!";
}
before
Method<?php
public function before($user, $ability)
{
if ($user->is_admin) {
return true; // Admins have full access
}
}
This method runs before other policy methods and grants full access to admins.
<?php
public function test_only_admins_can_access_admin_panel()
{
// Create an admin user
$admin = User::factory()->create(['is_admin' => true]);
$this->actingAs($admin);
$this->assertTrue(Gate::allows('access-admin-panel'));
// Create a regular user
$user = User::factory()->create(['is_admin' => false]);
$this->actingAs($user);
$this->assertFalse(Gate::allows('access-admin-panel'));
}
<?php
public function test_user_can_update_own_post()
{
$user = User::factory()->create();
$post = Post::factory()->create(['user_id' => $user->id]);
$this->assertTrue($user->can('update', $post));
$otherUser = User::factory()->create();
$this->assertFalse($otherUser->can('update', $post));
}
Run your tests using php artisan test
to ensure your authorization rules work as expected.
Laravel 12’s Gates and Policies are essential tools for managing user permissions. Gates offer a quick way to perform simple, general checks, while Policies provide a structured approach for model-specific authorization.
Remember:
With these tools, you can confidently control who does what in your Laravel application. Go ahead and start adding Gates and Policies to your project to keep your app safe and organized.
Happy coding!
No comments yet. Be the first to comment!
Please log in to post a comment:
Continue with Google