iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Software Development

Laravel 隨筆學習札記系列 第 27

Day27 - Gates 與 Policies:Laravel 中的權限管理解決方案

  • 分享至 

  • xImage
  •  

一樣來看看官方網站怎麼說 Laravel Authorization

In addition to providing built-in authentication services, Laravel also provides a simple way to authorize user actions against a given resource. For example, even though a user is authenticated, they may not be authorized to update or delete certain Eloquent models or database records managed by your application. Laravel's authorization features provide an easy, organized way of managing these types of authorization checks.

Laravel provides two primary ways of authorizing actions: gates and policies. Think of gates and policies like routes and controllers. Gates provide a simple, closure-based approach to authorization while policies, like controllers, group logic around a particular model or resource. In this documentation, we'll explore gates first and then examine policies.

You do not need to choose between exclusively using gates or exclusively using policies when building an application. Most applications will most likely contain some mixture of gates and policies, and that is perfectly fine! Gates are most applicable to actions that are not related to any model or resource, such as viewing an administrator dashboard. In contrast, policies should be used when you wish to authorize an action for a particular model or resource.

上面大概是在講說:

Laravel 提供了昨天提到的 authentication ,還有一種簡單的方法來授權使用者對特定資源的操作。像是使用者通過了身份驗證,就是登錄畫面了,他們也可能無權更新或刪除某些資料。在 Laravel 中,授權功能幫助我們可以有組織地管理授權限制。

Laravel 主要有兩種授權方法:gatespolicies,可以根據需求同時使用 gates 和 policies。

  • Gates:我們可以想像成簡單授權的檢查,類似 routes,gates 不涉及特定模型的操作,例如查看管理儀表板
  • Policies:像是將特定模型或資源相關的邏輯集中在一起,類似 controllers。policies 用於特定模型或資源的操作,可更具結構化和可擴展性。

Laravel Gates

Gates 是 Laravel 中用於授權的一種簡單方法,適合學習基礎的授權功能。

若是在構建複雜的應用時,會建議使用 Policies 來組織授權規則。

什麼是 Gates?

Gates 是一種閉包,負責判斷使用者是否被授權執行某個動作。

Gates 是在 App\Providers\AppServiceProvider 類別中使用 boot 方法定義,並使用 Gate facade

每個 Gate 都接收一個使用者實例作為第一個參數,並可選擇接收其他參數,如相關的 Eloquent 模型。

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
		//  定義一個名為update-post的gate判斷使用者的ID是否與創建該文章的使用者ID相同
    Gate::define('update-post', function (User $user, Post $post) {
        return $user->id === $post->user_id;
    });
}

使用 Policies 定義 Gates

Gates 也可以通過 callback array 來定義:

use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
 
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Gate::define('update-post', [PostPolicy::class, 'update']);
}

Authorizing Actions  授權操作

要使用 gates 授權某個操作,可以使用 allowsdenies 方法。

Laravel 會自動傳遞當前認證的使用者到 gate 閉包。

namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

// 在控制器中進行授權檢查
class PostController extends Controller
{
    /**
     * Update the given post.
     */
     
    // Request $request:接收一個 HTTP 請求對象,包含了使用者提交的數據。
		// Post $post:接收一個 Post 模型,從路由中獲取的特定文章。
    public function update(Request $request, Post $post): RedirectResponse
    {
        if (! Gate::allows('update-post', $post)) {
            abort(403);
        }
 
        // Update the post...
 
        return redirect('/posts');
    }
}

可以同時授權多個操作,使用 anynone 方法

if (Gate::any(['update-post', 'delete-post'], $post)) {
    // 該用戶可以更新或刪除文章
}

if (Gate::none(['update-post', 'delete-post'], $post)) {
    // 該用戶無法更新或刪除文章
}

Gates 回應

Gates 使用 Response 可以返回更詳細的回應,包括錯誤訊息。

  • 定義授權規則: 返回詳細的授權回應,檢查使用者是否為管理員

    use App\Models\User;
    use Illuminate\Auth\Access\Response;
    use Illuminate\Support\Facades\Gate;
    
    Gate::define('edit-settings', function (User $user) {
        return $user->isAdmin
                    ? Response::allow()
                    : Response::deny('You must be an administrator.');
    });
    
  • 檢查授權回應:

    • 使用 Gate::allows 方法:返回簡單的布林值
    • 使用 Gate::inspect 方法:獲取完整的授權回應
    $response = Gate::inspect('edit-settings');
    if ($response->allowed()) {
        // 動作已授權...
    } else {
        echo $response->message();
    }
    

Customizing The HTTP Response Status

  • 使用 denyWithStatus 方法:當授權檢查失敗時,返回自定義的 HTTP 狀態碼,此更有靈活性

    Gate::define('edit-settings', function (User $user) {
        return $user->isAdmin
                    ? Response::allow()
                    : Response::denyWithStatus(404);
    });
    
  • 使用 denyAsNotFound 方法:當使用者未獲得授權時隱藏資源,返回 404 錯誤碼,此方法更簡潔及易於閱讀、使用

    Gate::define('edit-settings', function (User $user) {
        return $user->isAdmin
                    ? Response::allow()
                    : Response::denyAsNotFound();
    });
    

Creating Policies

policy 是用來管理特定模型或資源的授權邏輯的類別。

例如,在一個部落格,我們可能會有一個 App\Models\Post 模型(代表文章),以及一個對應的 App\Policies\PostPolicy 來決定使用者是否可以創建或更新文章。

Generating Policies

使用 Artisan 命令 make:policy 生成一個 policy,生成的 policy 將放在 app/Policies 目錄中,如果該目錄不存在,Laravel 會自動幫我們創建

php artisan make:policy PostPolicy

若是需要生成一個包含常見CRUD(如查看、創建、更新和刪除)範例方法,可以在命令中添加 --model 選項:

php artisan make:policy PostPolicy --model=Post

Registering Policies

在 Laravel 中,只要 model 和 policy 遵循標準命名規則,Laravel 會自動 Policy Discovery

  1. 資料夾位置
    • policy 必須放在名為 Policies 的資料夾中,該資料夾應位於或高於包含 model 的資料夾。
    • 例如,model 可以放在 app/Models 中,而 policy 則放在 app/Policies 中。
  2. 命名規則
    • policy 的名稱必須與對應 model 名稱一致,並以 Policy 為後綴。
    • 例如,User model 的對應政策應為 UserPolicy

Manually Registering Policies

如果您想要定義自己的 policy,可以使用 Gate::guessPolicyNamesUsing 方法註冊自定義回傳。這個方法通常在應用程序 AppServiceProviderboot 方法中

use App\Models\Order;
use App\Policies\OrderPolicy;
use Illuminate\Support\Facades\Gate;
 
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Gate::policy(Order::class, OrderPolicy::class);
}

Writing Policies

Policy Methods

當我們生成 Policy 後,就可以為每一個授權的行動添加方法了。

我們可以在 PostPolicy 中定義一個 update 方法,用來判斷一個使用者是否可以更新一篇文章。

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    /**
     * 確定使用者是否可以更新指定的文章。
     */
     
    // update 方法接收兩個參數:一個 User 物件和一個 Post 物件
    // 返回 true 或 false,告訴我們這位使用者是否有權更新這篇文章
    public function update(User $user, Post $post): bool
    {
		    // 檢查使用者的 ID 是否與文章的 user_id 相符
        return $user->id === $post->user_id;
    }
}

可以根據需求在 Policy 中定義其他方法,例如 viewdelete,以授權不同的操作。

如果使用 --model 選項生成策略,則會自動生成查看、創建、更新、刪除等相關的方法。

Policy Responses

Policy 使用 Response 可以返回更詳細的回應,包括錯誤訊息。

  • 定義授權規則: 返回詳細的授權回應,檢查使用者是否有權限
use App\\Models\\Post;
use App\\Models\\User;
use Illuminate\\Auth\\Access\\Response;

public function update(User $user, Post $post): Response
{
    return $user->id === $post->user_id
                ? Response::allow()
                : Response::deny('You do not own this post.');
}
  • 檢查授權回應:
    • 使用 Gate::allows 方法:返回簡單的布林值
    • 使用 Gate::inspect 方法:獲取完整的授權回應
$response = Gate::inspect('update', $post);

if ($response->allowed()) {
    // 行動被授權...
} else {
    echo $response->message();
}

Middleware 和 身份驗證 (Authentication) 以及 授權 (Authorization)

概念 Middleware 身份驗證 (Authentication) 授權 (Authorization)
定義 位於請求和回應過程中的中介層,用於攔截和處理請求 確認使用者的身份 確定使用者對資源的訪問權限
功能 可以進行請求過濾、數據處理、日誌記錄等 驗證用戶的憑證(如用戶名和密碼) 根據使用者角色和權限檢查訪問許可
問題 主要用於處理請求過程中的邏輯 你是誰? 你能做什麼?
示例 驗證請求、日誌記錄、CORS 處理 登錄電子郵件帳號 決定使用者能否發送或刪除郵件
實施方式 通過創建和註冊 middleware 來使用 使用登錄表單、社交媒體登錄或生物識別 定義角色、權限和政策

參考資料:

  1. Laravel — Security — Authorization
  2. Laravl官方網站 - Authorization

踏著身心靈的塔羅腳步,轉向技術與邏輯的工程師之路,就藉由塔羅日抽來紀錄今日的學習與生活吧!

愚人牌:好唷!就是照自己想法寫下去,就對了~

“If you don’t get out of the box you’ve been raised in, you won’t understand how much bigger the world is.”

如果不跳脫出你從小到大養成的框架,你永遠不會知道這個世界有多大。

- Angelina Jolie


上一篇
Day26 - 簡化認證:用 Laravel Authentication 建立使用者登入
下一篇
Day28 - Eloquent 資源的魔法:讓 API Resources 輸出更簡單
系列文
Laravel 隨筆學習札記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言