Posted in Laravel 5 筆記

Laravel 5 – Gate & permissions

https://laravel.com/docs/5.8/authorization#writing-gates

使用者的操作權限,之前都是用Policy,沒用過Gate,覺得比較難理解。用Policy的前提是有一個對應的Model(文件裡又稱為resource),檢查使用者對這個Model有沒操作權限。

Gate寫在Closure裡比較有彈性,可以像Policy的判斷,也可以自定義,不用綁Model,例如超級管理員的權限檢查跟任何Model都沒關係。

Gate的定義:一般放在AuthServiceProvider,或要新增另一個Provider放也可以。

// 定義
// AppServiceProvider.php

public function boot()
{
    Gate::define('update-post', function ($user, $post) {
        // 條件
        return $user->id === $post->user_id;
    });

    // 其他 Gate 定義
    // Gate::define(...
    // Gate::define(...

    Gate::define('delete-post', function ($user) {
        // 條件
        return $user->is_admin;
    });
}

Provider裡頭定義所有的Gate是全域型的,任何地方都可以使用來檢查權限。底下以allows與denies檢查權限。

allows:是否有該操作權限?

底下的code涵義為當前使用者對這一筆$post是否有更新權限,則要看上方「udpate-post」裡的匿名函數返回true或false。

// web.php
Route::get('/', function () {
    $post = \App\Post::find(1);
    dd(\Gate::allows('update-post', $post));  // return boolean

    // 同上
    // dd($user->can('update-post', $post));
});

denies:將allows的結果反轉,亦即當前使用者是否沒有操作權限。

假設當前使用者並不是管理者,allows返回false,不允許刪除的操作;denies返回true,否定刪除操作 (這裡譨腦要轉一下)。所以都是不可以刪除的意思。

// web.php
Route::get('/', function () {
    dd(\Gate::allows('delete-post'));  // return false
    dd(\Gate::denies('delete-post'));  // return true

    // 同上
    // dd($user->can('delete-post'));
    // dd($user->cant('delete-post'));
});

codecourse筆記,一次性把多個權限檢查加入Gate定義中。

Permission Model:所有權限的名稱 (update-post, delete-post, …)

users_permissions:紀錄User與Permission多對多的關聯(pivot table)。

// AppServiceProvider.php
public function boot()
{
    Permission::get()->map(function ($permission) {
        Gate::define($permission->name, function ($user) {
            return $user->hasPermissionTo($permission);
        });
    });
}

先不管code當中的return $user->…,map()的動作只是把每一個permission的名稱與Gate Closure綁在一起,跟前面例子一行一行跟Gate綁定是一樣的。

再來看看真的要檢查權限時,laravel怎麼運作?例如,$user->can(‘create-post’),laravel就會找上述Gate::define(‘create-post’, function () { … }),的Closure檢查權限。Closure檢查權限的部分是呼叫hasPermissionTo(例如帶入的是create-post物件)。

// User.php
public function hasPermissionTo($permission)
{
    return $this->hasPermission($permission);
}

public function hasPermission($permission)
{
    // 當前使用者的所有權限撈出來 (collection)
    // 判斷$permission是否有在這其中 (有的話, count() = 1)
    // 再轉成布林值返回
    return (bool) $this->permissions->where('name', $permission->name)->count();
}

public function permissions()
{
    return $this->belongsToMany(Permission::class, 'users_permissions');
}

以$user->can(‘create-post’)來說,當返回true就表示使用者有這個權限(users_permission裡頭有create-post),而返回false表示沒這個權限(users_permission裡頭沒有create-post)。

真的很難理解,應該是Closure的關係 = =。

Leave a comment