iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0
Modern Web

後端菜雞仔想學 Laravel系列 第 26

Middleware 會員權限設計:做出工作識別證!

  • 分享至 

  • xImage
  •  

小食譜06-2:會員權限設計

情境想像

「線上產品瀏覽系統」是提供消費者線上查看產品資訊,並沒有做購物車結帳功能、串金流。
所以我希望做一個簡單的會員系統,消費者需要註冊會員,登入後才能查看產品,讓我能夠掌握這些消費者的資訊。
除了可以會員行銷,後續結帳有什麼問題也有會員資訊能核對。

會員權限列表

權限 說明
管理員 1. 瀏覽所有產品、類別資料
2. 查詢特定產品、類別資料
3. 關鍵字搜尋
4. 產品及類別所有的新增、刪除、修改操作
一般會員 1. 瀏覽所有產品資料
2. 查詢特定產品資料
3. 關鍵字搜尋

動手做做看

要在 users 表中加入 role 欄位來區分「管理員」和「一般會員」的權限。

建立新的 migration 來更新 users 表

php artisan make:migration add_role_to_users_table --table=users

修改新的 migration 檔案

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddRoleToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('role')->default('一般會員')->after('password'); // 在 'password' 欄位後新增 'role'
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('role');
        });
    }
}

執行 migration

php artisan migrate

要選擇 Middleware 還是 Policy?

根據我的需求:

  • 目前基於 role 欄位來區分「管理員」和「一般會員」的權限,這樣的邏輯是比較簡單的,所以使用 Middleware 即可。
  • 如果預計未來會需要更多的權限控制,例如針對特定產品、訂單等資源進行更複雜的控制,那麼使用 Policy 會更合適。

備註

Laravel 11 的版本有大改動,如果需要註冊 Middleware 要到 bootstrap/app.php檔案中操作。
但 Laravel 11 自動處理了許多常用的 Middleware,像是 auth、throttle 這些已經預先設定好,所以可以直接在路由上使用 Middleware,而不需要再像以前那樣手動去 Kernel.php 註冊。

更多相關資訊可以參考以下文章:


會員權限設定步驟:

  1. 在 User 模型中定義角色檢查方法。
  2. 建立 Middleware 處理權限檢查。
  3. 指派 Middleware 給特定的路由。
  4. 使用不同權限的帳號測試路由,確保權限邏輯正常。

定義會員角色

打開 User.php 定義簡單的方法來區分管理員和一般會員:

    /**
     * Check if the user has a specific role.
     *
     * @param string $role
     * @return bool
     */
    public function hasRole($role)
    {
        return $this->role === $role;
    }

這樣 $role 可以是 ‘管理員’ 或是 ‘一般會員’,甚至是 ‘VIP會員’ 等等,使用此方法未來會方便擴展使用及維護。

建立 Middleware

php artisan make:middleware RoleMiddleware

編輯 Middleware

在剛剛建立的 RoleMiddleware 中,編輯 handle 方法來檢查會員的權限:

public function handle($request, Closure $next, $role)
{
    // 檢查會員是否已登入,且會員的權限是否符合要求
    if (!$request->user() || $request->user()->permission !== $role) {
        // 如果會員未登入或權限不符合,回傳一個 403 的 JSON 錯誤回覆
        return response()->json(['error' => '權限不足'], 403);
    }

    // 如果權限符合要求,將請求傳遞給下一個中介層或控制器
    return $next($request);
}

指派 Middleware 給特定路由

可以在路由中使用 Middleware 來限制訪問權限。
像是工作識別證!

打開 api.php :

先前使用 JWT 已經有一個 Middleware 是登入驗證:

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

我的理解:

將這個登入驗證的 Middleware 變成一個大圈圈組別,也代表所有登入的一般會員,裡面有一個小圈圈是管理員。

  • auth:api :登入驗證。
  • RoleMiddleware :授權。
use App\Http\Middleware\RoleMiddleware;

Route::middleware('auth:api')->group(function () {

    // 所有登入的會員都可以查看所有或特定產品資料、關鍵字搜尋
    Route::get('products', [ProductController::class, 'index']);
    Route::get('products/{product}', [ProductController::class, 'show']);

    // 只有管理員可以進行新增操作
    Route::post('products', [ProductController::class, 'store'])->middleware(\App\Http\Middleware\RoleMiddleware::class . ':管理員');

    // 只有管理員可以進行更新操作
    Route::patch('products/{product}', [ProductController::class, 'update'])->middleware(\App\Http\Middleware\RoleMiddleware::class . ':管理員');

    // 只有管理員可以進行刪除操作
    Route::delete('products/{product}', [ProductController::class, 'destroy'])->middleware(\App\Http\Middleware\RoleMiddleware::class . ':管理員');
});

授權邏輯

  • 指定 RoleMiddleware 檢查當前使用者是否具有「管理員」角色。
  • 如果使用者不是「管理員」,RoleMiddleware 會阻止他們執行這些操作,並回傳一個 403 未授權的回應。

使用 Postman 測試

1. 註冊 2 個測試帳號

2. 手動調整權限

打開 MySQL Workbench 將其中一個帳號手動調整權限為「管理員」。

UPDATE users SET role = '管理員' WHERE id = [user_id];

3. 登入測試帳號

  • 先用管理員和一般會員的帳號分別登入,取得兩個不同的 JWT。
  • 然後嘗試取得該帳號的會員資料,確認此 token 可以使用。

一般會員:

選擇 Bearer Token:{{token}}

https://ithelp.ithome.com.tw/upload/images/20241010/201693001wUz1U9Jop.jpg

按下 Send 後:

{
    "id": 1,
    "name": "Test User1",
    "email": "test2@example.com",
    "email_verified_at": null,
    "role": "一般會員",
    "created_at": "2024-08-27 15:16",
    "updated_at": "2024-08-27 15:16"
}

管理員:

選擇 Bearer Token:{{token}}

https://ithelp.ithome.com.tw/upload/images/20241010/20169300d7c0b78mAR.jpg

按下 Send 後:

{
    "id": 2,
    "name": "Test User2",
    "email": "test2@example.com",
    "email_verified_at": null,
    "role": "管理員",
    "created_at": "2024-08-27 15:18",
    "updated_at": "2024-08-27 15:18"
}

4. 測試產品查詢(所有帳號)

https://ithelp.ithome.com.tw/upload/images/20241010/201693000djOVeWiib.jpg

  • 測試管理員和一般會員都可以成功取得產品列表。

5. 測試產品新增(僅限管理員)

https://ithelp.ithome.com.tw/upload/images/20241010/20169300SrahZO6ojQ.jpg

  • 測試管理員成功新增產品。

https://ithelp.ithome.com.tw/upload/images/20241010/20169300kDCqi0Ncyz.jpg

  • 測試一般會員嘗試新增產品,回傳 403 未授權。

6. 測試產品更新(僅限管理員)

https://ithelp.ithome.com.tw/upload/images/20241010/20169300zxvZotcZ1p.jpg

  • 測試管理員成功更新產品。

https://ithelp.ithome.com.tw/upload/images/20241010/20169300eoi0jcilXV.jpg

  • 測試一般會員嘗試更新產品,回傳 403 未授權。

7. 測試刪除產品(僅限管理員)

https://ithelp.ithome.com.tw/upload/images/20241010/2016930004BJhnuqmP.jpg

  • 測試管理員成功刪除產品。

https://ithelp.ithome.com.tw/upload/images/20241010/20169300XxDYfz5jfT.jpg

  • 測試一般會員嘗試刪除產品,回傳 403 未授權。

上一篇
建立註冊、登入、登出流程:再指派一位店長吧!
下一篇
第三方登入:不用花時間註冊會員好方便!
系列文
後端菜雞仔想學 Laravel30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言