Laravel ‐ chapter 16 - pierre-akhrass/Lavarel-Docs GitHub Wiki
Chapter 16: Gates and Policy (Authorization)
Authentication vs Authorization
- Authentication: Verifies identity via credentials (e.g., login).
- Authorization: Defines what the user can do in the system (e.g., edit, delete, view).
What is a Gate?
Gates are closures that determine if a user can perform an action.
use Illuminate\Support\Facades\Gate;
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
Gate Elements:
- Uses
Gate
Facade. - Defines a key like
'update-post'
. - Implements the authorization rule.
Preparing for Gates
- Create migration:
php artisan make:migration add_user_id_to_posts_table
This will add a foreign key column to an existing table: posts.
- Define foreign key:
$table->foreignId('user_id')->constrained()->onDelete('cascade');
If a user is deleted, all their posts will be deleted automatically (cascade delete).
- Run fresh migration:
php artisan migrate:fresh
-
Drops all tables in the database.
-
Recreates them from scratch using all migration files.
-
Useful during development, but be careful — it deletes all data.
- Update
Post
model:
protected $fillable = [..., 'user_id'];
- Update factory (
PostFactory.php
) and seeder (PostSeeder.php
) to assignuser_id
.
PostFactory.php
use App\Models\User;
public function definition()
{
return [
'title' => $this->faker->sentence,
'content' => $this->faker->paragraph,
'user_id' => User::factory(), // ← creates a new user and links it
];
}
PostSeeder.php
Post::factory()->count(10)->create();
Using Gates
Define in AppServiceProvider.php
:
Gate::define('update-post', fn($user, $post) => $user->id == $post->user_id);
Use in PostController.php
:
if (!Gate::allows('update-post', $post)) {
abort(403);
}
This checks authorization — specifically, whether the currently logged-in user is allowed to update a given post. If they are not authorized, the request is aborted with a 403 Forbidden error.
Using Policies
Use policies to group multiple authorization rules for a model.
When to Use Policies
- When you need rules for multiple actions on a model.
- For maintainability and clarity.
Creating a Policy
php artisan make:policy PostPolicy --model=Post
Defines methods like:
public function view(User $user, Post $post): bool { return true; }
public function create(User $user): bool { return $user->id > 0; }
public function update(User $user, Post $post): bool { return $user->id == $post->user_id; }
public function delete(User $user, Post $post): bool { return $user->id == $post->user_id; }
Registration
Policies are auto-discovered if:
- Located in
app/Policies
- Match naming:
PostPolicy
forPost
model
Using Policy Methods
Gate::allows('update', $post)
Returns true if the current user is allowed to perform the 'update' action on the $post.
Gate::denies('delete', $post)
Returns true if the user is NOT allowed to delete the post.
In controller:
if (!Gate::allows('index', $posts[0])) {
abort(403);
}
This checks if the current user is allowed to perform the 'index' action on the first post in the list ($posts[0]).
Return Responses from Policy
public function update(User $user, Post $post): Response
{
return $user->id == $post->user_id
? Response::allow()
: Response::deny('You do not own this post.');
}
Use:
Gate::inspect('update', $post)
Updating Post Creation
User model (User.php
):
public function posts() {
return $this->hasMany(Post::class);
}
Controller:
$post = new Post($request->validated());
$user = Auth::user();
$user->posts()->save($post);
Gate Helper Methods
Gate::check('create', $post)
Gate::any(['update', 'delete'], $post)
Gate::none(['update', 'delete'], $post)
Auth::user()->can('create', $post)
Auth::user()->cannot('create', $post)
Gate::forUser($user)->allows('update-post', $post)
Gate::forUser($user)->denies('update-post', $post)
allowIf() and denyIf()
Gate::allowIf(fn(User $user) => $user->isAdmin())
Gate::denyIf(fn(User $user) => !$user->isAdmin())
Equivalent:
function (User $user) {
return !$user->isAdmin();
}
Gate::authorize()
Gate::authorize('update', $post);
Throws an exception if not authorized.