Giao diện
Authorization (Phân quyền)
Giới thiệu (Introduction)
Ngoài authentication, Laravel cũng cung cấp cách đơn giản để phân quyền (authorize) user actions trên resources. Ví dụ: dù user đã authenticated, họ có thể không được phép update hay delete certain Eloquent models.
Laravel cung cấp 2 cách chính:
| Phương pháp | Khi nào dùng |
|---|---|
| Gates | Closure-based, đơn giản — cho actions không liên quan đến model (ví dụ: xem admin dashboard) |
| Policies | Class-based — cho actions liên quan đến model/resource cụ thể |
Bạn có thể kết hợp cả hai trong ứng dụng.
Gates
Viết Gates
Định nghĩa trong AppServiceProvider method boot:
php
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});Authorize Actions qua Gates
php
use Illuminate\Support\Facades\Gate;
// Kiểm tra
if (Gate::allows('update-post', $post)) {
// User có thể update...
}
if (Gate::denies('update-post', $post)) {
// User không được phép...
}
// Authorize (throw exception nếu denied)
Gate::authorize('update-post', $post);
// Kiểm tra nhiều abilities
if (Gate::any(['update-post', 'delete-post'], $post)) {
// User có thể update HOẶC delete...
}
if (Gate::none(['update-post', 'delete-post'], $post)) {
// User KHÔNG thể update NÀ delete...
}Gate Responses
Trả về response chi tiết thay vì boolean:
php
use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::deny('Bạn phải là quản trị viên.');
});Intercepting Gate Checks
php
Gate::before(function (User $user, string $ability) {
if ($user->isAdmin()) {
return true; // Super admin bypass mọi kiểm tra
}
});
Gate::after(function (User $user, string $ability, bool|null $result) {
// Chạy sau mỗi authorization check...
});Inline Authorization
php
use Illuminate\Support\Facades\Gate;
Gate::allowIf(fn (User $user) => $user->isAdmin());
Gate::denyIf(fn (User $user) => $user->banned());Policies
Tạo Policies
bash
php artisan make:policy PostPolicy --model=PostĐăng ký Policies
Laravel tự động phát hiện policies theo convention {Model}Policy. Đăng ký thủ công (nếu cần):
php
use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
Gate::policy(Post::class, PostPolicy::class);Viết Policy Methods
php
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* User có thể xem post?
*/
public function view(User $user, Post $post): bool
{
return true;
}
/**
* User có thể tạo posts?
*/
public function create(User $user): bool
{
return true;
}
/**
* User có thể update post?
*/
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
/**
* User có thể xóa post?
*/
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}Policy Responses
php
use Illuminate\Auth\Access\Response;
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('Bạn không sở hữu bài viết này.');
}Methods Without Models
Một số actions không liên quan đến model instance:
php
public function create(User $user): bool
{
return $user->role === 'writer';
}Guest Users
Mặc định gates và policies trả về false cho guest. Type-hint nullable:
php
public function update(?User $user, Post $post): bool
{
return $user?->id === $post->user_id;
}Policy Filters
php
public function before(User $user, string $ability): bool|null
{
if ($user->isAdmin()) {
return true; // Admin bypass tất cả
}
return null; // Tiếp tục kiểm tra policy method
}Authorize Actions qua Policies
Qua User Model
php
if ($request->user()->can('update', $post)) {
// ...
}
if ($request->user()->cannot('update', $post)) {
// ...
}
// Actions không cần model instance
if ($request->user()->can('create', Post::class)) {
// ...
}Qua Gate Facade
php
use Illuminate\Support\Facades\Gate;
Gate::authorize('update', $post);Qua Controller Helper
php
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// User được phép update...
}Qua Middleware
php
Route::put('/post/{post}', function (Post $post) {
// ...
})->middleware('can:update,post');
// Actions không cần model
Route::post('/post', function () {
// ...
})->middleware('can:create,App\Models\Post');Qua Blade Templates
blade
@can('update', $post)
<!-- User có thể update -->
@elsecan('create', App\Models\Post::class)
<!-- User có thể tạo -->
@else
<!-- Không có quyền -->
@endcan
@cannot('update', $post)
<!-- User không thể update -->
@endcannot
@canany(['update', 'view', 'delete'], $post)
<!-- User có ít nhất một quyền -->
@endcananyAuthorization & Inertia
Truyền authorization data vào Inertia responses:
php
use App\Models\Post;
return Inertia::render('Posts/Index', [
'posts' => Post::all()->map(function (Post $post) {
return [
'id' => $post->id,
'title' => $post->title,
'can' => [
'update' => $request->user()->can('update', $post),
'delete' => $request->user()->can('delete', $post),
],
];
}),
]);