介紹如何在 Laravel 網頁專案中使用 Gates 功能,實做使用者角色與權限分級,區分一般使用者與管理者。
首先參考 Laravel 6 建立含有使用者註冊、登入認證功能的網頁專案教學,建立好基本的 Laravel 專案,但不要執行 migrate
。
假設我們希望將使用者區分為一般使用者(user
)、一般管理者(manager
)與系統管理者(admin
)三類,分別授予不同的權限。
編輯 app/User.php
,加入三種帳號角色名稱的常數字串,並將 role
這個欄位加入 fillable
中:
class User extends Authenticatable { // ... const ROLE_ADMIN = 'admin'; const ROLE_MANAGER = 'manager'; const ROLE_USER = 'user'; protected $fillable = [ 'name', 'email', 'password', 'role', ]; // ... }
編輯 database/migrations/2014_10_12_000000_create_users_table.php
這一個建立使用者資料表的 migration 設定檔,在其中加入一欄用於儲存帳號角色的 role
欄位:
use App\User; class CreateUsersTable extends Migration { // ... public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('role')->default(User::ROLE_USER); // 加入角色欄位 $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } }
修改好之後,回到 Laravel 專案目錄,執行 migrate
:
# 建立資料庫結構
php artisan migrate
編輯 app/Http/Controllers/Auth/RegisterController.php
,設定使用者註冊時的角色都是一般使用者:
protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), 'role' => User::ROLE_USER, // 預設為一般使用者 ]); }
建立自訂的 Gate 權限規則,以判斷每位使用者是否有權限執行特定的動作。
編輯 app/Providers/AuthServiceProvider.php
,加入自訂的 Gates 規則:
use App\User; class AuthServiceProvider extends ServiceProvider { // .. public function boot() { $this->registerPolicies(); // 系統管理者 Gate 規則 Gate::define('admin', function ($user) { return $user->role === User::ROLE_ADMIN; }); // 一般管理者 Gate 規則 Gate::define('manager', function ($user) { return $user->role === User::ROLE_MANAGER; }); // 一般使用者 Gate 規則 Gate::define('user', function ($user) { return $user->role === User::ROLE_USER; }); } }
這樣三種角色的基本權限就設定完成了,接下來就可以在 Laravel 專案的各種地方運用這些權限設定。
在 Blade 樣板中可以運用 @can
、@cannot
或 @canany
來判斷使用者的權限(詳細用法可參考 Laravel 的文件):
@can('admin') <!-- 系統管理者 --> @elsecan('manager') <!-- 一般管理者 --> @else <!-- 一般使用者 --> @endcan
若在 Controller 中則可使用 Gate::allows
或 Gate::denies
判斷使用者權限:
use Illuminate\Support\Facades\Gate; class Controller extends BaseController { // ... public function someAction() { if (Gate::allows('admin')) { return '系統管理者。'; } if (Gate::denies('admin')) { return '非系統管理者!'; } } }
另外一種方式是運用 authorize
直接限制整個函數的執行權限:
class Controller extends BaseController { // ... // 只有系統管理者可以執行 public function adminAction() { $this->authorize('admin'); // ... } }
在 Middleware 中也可以使用 Gate 的權限設定,例如應用在 Route 之中:
// 只有系統管理者可以執行 Route::get('/someAction', 'MyController@someAction') -> middleware('can:admin');
在這裡的實作中,帳號的權限是根據 role
欄位值所決定的,要更改帳號權限的話,可以直接從資庫中更改,或是透過 Laravel 的 Tinker 環境快速設定:
# 進入 Tinker 互動式指令環境
php artisan tinker
然後在 Tinker 環境中,以一般的 PHP 語法直接更改使用者的 role
屬性:
# 將 demo@gmail.com 帳號設為系統管理者 use App\User; User::where('email', 'demo@gmail.com') -> update(['role' => User::ROLE_ADMIN]);
若需要讓系統管理者有網頁介面可以設定帳號權限,可參考上面這個 PHP 語法,自己設計修改帳號的使用者介面。