Laravel Gates

Tổng quan về Gates:

  • Gates là simply closures, xác định xem người dùng có quyền hay không với một hành động cụ thể.
  • Gates được sử dụng cả ở template blade, routes, controller. Gates sẽ không gắn với model cụ thể nào, gate sẽ sử dụng các thông tin truyền vào với tham số đầu tiên là user.
  • Gates được viết (định nghĩa) ở App\Providers\AuthServiceProvider.

1. Khởi tạo Gates:

  • Khởi tạo Gates trong App\Providers\AuthServiceProvider:
<?php namespace App\Providers;

    use App\Models\User;
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
    use Illuminate\Support\Facades\Gate;

    class AuthServiceProvider extends ServiceProvider
    {
        /**
         * The policy mappings for the application.
         *
         * @var array
         */
        protected $policies = [
            'App\Models\Model' => 'App\Policies\ModelPolicy',
        ];

        /**
         * Register any authentication / authorization services.
         *
         * @return void
         */
        public function boot()
        {
            $this->registerPolicies();
            $this->setGates();
        }

        private function setGates()
        {
            Gate::define('update-post', function (User $user,  Post $post) {
                return $user->id === $post->user_id;
            });
        }
    }
  • Định nghĩa một gate là update-post mục đính xác định xem user có quyền update bài viết hay không.
  • Tham số đầu tiên truyền vào được mặc định là user đang đăng nhập, tiếp theo truyền vào các tham số ở đây là bài viết muốn cập nhật.
  • Hàm trả về giá trị true hoặc fales nếu true thì user có quyền update bài viết và ngược lại.

2. Sử dụng Gates.

Trong controller:

  • Sử dung Method allows xác định xem Gate có cho phép hành động diễn ra hay không:
if (Gate::allows('update-post', $post)){ 
// Update the post... 
} 
  • Sử dụng Method denies để từ chối hành động diễn ra:
if (Gate::denies('update-post', $post)) {
    // The user can't update the post...
}
  • Sử dụng Method forUser để kiểm tra quyền của user khác user đang đăng nhập:
if (Gate::forUser($user)->allows('update-post', $post)) {
    // The user can update the post...
}
  • Sử dụng Method anynone để sử dụng nhiều Gate kiểm tra một hành động xem có được phép diễn ra hay không:
if (Gate::any(['update-post', 'delete-post'], $post)) {
    // The user can update or delete the post...
}

if (Gate::none(['update-post', 'delete-post'], $post)) {
    // The user can't update or delete the post...
}
  • Ngoài ra còn một số method khác check, authorize, inspect, can, cannot.

Trong Middleware:

Route::post('/update-post', [App\Http\Controllers\PostController::class, 'update'])->can('update-post');
  • Trong ví dụ trên kiểm tra user có quyền update-post trước khi tới rquest tới controller.

Trong Blade Templates:

@can('update-post', $post)
    <!-- The current user can update the post... -->
@endcan
  • Ở đây màn hình chỉ hiển thị các bài viết mà user đang đăng nhập có quyền cập nhật.

3. Kết luận.

  • Chúng ta đã tìm hiểu thêm một công cụ giúp giải quyết bài toán phân quyền trong Laravel ngoài Middleware và Policy.
  • Gates thường được sử dụng ở tầng Controller, giúp kiểm soát quyền của các user trong hệ thống một cách dễ dàng (logic phần quyền được viết tập chung ở AuthServiceProvider).


Tài liệu tham khảo:
https://laravel.com/docs/8.x/authorization#gates
https://www.php.net/manual/en/class.closure.php