iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
1
自我挑戰組

Laravel 實戰經驗分享系列 第 24

Laravel 實戰經驗分享 - Day24 過濾從 HTTP 來的 requests - Middleware

今天比較早開始寫文章,既然沒有上班,就可以好好的深入研究一些 Laravel 的用法,看看自己有沒有什麼地方寫爛需要改進的。

今天來講 Laravel 的 Middleware,我們在 Day18 的 JWT 實作也有用到 Middleware 進行權限的判斷,以防止沒有 token 認證的請求。

public function __construct()
{
    $this->middleware('auth:api', ['except' => ['login']]);
}

事實上 Middleware 主要就是協助我們在進行 HTTP 請求時檢查這個請求來源是否符合我們在裡面設定的規則,可以進行許多認證的工作,不用再寫在每一個 Controller 的 function 內了,Laravel 預設也放了一些 Middleware 進去,大多是認證相關或是 CSRF 的保護機制。

創建 Middleware

透過 Artisan 建立一支 Middleware

php artisan make:middleware CheckRoles

我們來建立一支判斷使用者權限的 Middleware,首先除了原先的 users 表以外,也要先建立一張資料表紀錄目前這個系統的所有權限名稱。

<?php

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

class CreateRolesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name', 100);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('roles');
    }
}

使用者可能會有不同的權限,而每個權限下面也會有不同的使用者,因此權限對使用者是多對多的關係,所以在 usersroles 表外,也需要一張對應表 user_roles 紀錄兩張表多對多的關係。

<?php

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

class CreateUserRolesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('user_roles', function (Blueprint $table) {
            $table->unsignedBigInteger('user_id');
            $table->unsignedBigInteger('role_id');

            $table->index(["user_id"], 'fk_users_has_roles_users_idx');

            $table->index(["role_id"], 'fk_users_has_roles_roles_idx');

            $table->foreign('user_id', 'fk_users_has_roles_users_idx')
                ->references('id')->on('users');

            $table->foreign('role_id', 'fk_users_has_roles_roles_idx')
                ->references('id')->on('roles');
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('user_roles');
    }
}
php artisan migrate

以上設置在資料庫的關聯中會長這樣。

Model 設置

進入 app/Models/User.php 內新增以下程式碼

public function roles()
{
return $this->belongsToMany('App\Role', 'user_roles', 'user_id', 'role_id');
}

return $this->belongsToMany('對應的 Model', '中間的對應表', '外鍵 1', '外鍵 2');

以上是除了在資料庫設定關聯外,也利用 Laravel 建立兩個 Model 多對多的關聯,可以讓你直接操作 Model,這部分我在之前建立資料庫的關聯忘記提及,之後再找時間把這塊補上 TAT。

建資料內容這邊不多提及,可利用 Laravel Seeder 的方法或是直接進入資料庫內進行操作都可以,我們預設的資料如下圖。

users

roles

user_roles

定義你的 Middleware 規則

我們先到 routes/api 設定需要這個 Middleware 檢查的 Controller

Route::group([
  // role:admin 代表你要在 Middleware 中設置變數 $role = admin
  'middleware' => ['auth:api', 'role:admin'],
], function () {
  Route::post('roles', [RolesController::class, 'store']);  
});

接下來就到 app/Http/CheckRoles 內的 function handle 寫入這個權限的規則。

public function handle($request, Closure $next, $role)
{
    // 透過 JWT 取得你的身份
    $user                    = Auth::user();
    // 從資料庫拉出你的權限
    $system_roles            = $user->roles;
    switch ($role) {
      case 'admin':
        foreach ($system_roles as $system_role) {
          if($system_role->name == "admin"){
            // $next($request) 就是讓你的請求可以通過的意思
            return $next($request);
          }
        }
    return response()->json([
        'message' => '您沒有權限進行此動作'
    ], 403);
}

如此一來,Middleware 可以在前端 POST /api/roles 時進行權限檢查,若是不符合你所設定的權限,則會先行 return 403 狀態,也完成了透過後端檢查權限的功能囉!


上一篇
Laravel 實戰經驗分享 - Day23 別再用 FTP 了,Gitlab CI 的簡單部署教學
下一篇
Laravel 實戰經驗分享 - Day25 Dockerize 你的 Laravel 專案(上)
系列文
Laravel 實戰經驗分享30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言