Spatie Permissions: Bouncer quyền lực cho ứng dụng Laravel của bạn
Lavarel

Spatie Permissions: Bouncer quyền lực cho ứng dụng Laravel của bạn

Author

Admin System

@root

Ngày xuất bản

20 Mar, 2026

Lượt xem

2 Lượt

Spatie_Permissions

Chào các chiến hữu code! Hôm nay, Creyt sẽ đưa anh em dạo quanh một khu phố VIP của Laravel, nơi mà quyền lực được phân chia rõ ràng, rành mạch. Anh em cứ hình dung thế này: ứng dụng của chúng ta là một tòa nhà chọc trời, mỗi tầng là một tính năng, mỗi căn phòng là một hành động cụ thể. Và không phải ai cũng có chìa khóa vạn năng để mở mọi cánh cửa, đúng không? Đó là lúc chúng ta cần một hệ thống an ninh “xịn sò” để cấp phát và quản lý chìa khóa. Và ngôi sao sáng nhất trong lĩnh vực này chính là Spatie Laravel Permissions.

Spatie Laravel Permissions là gì và để làm gì?

Đơn giản mà nói, Spatie Laravel Permissions là một gói (package) cực kỳ mạnh mẽ và được cộng đồng tin dùng, giúp chúng ta quản lý quyền hạn (permissions)vai trò (roles) của người dùng trong ứng dụng Laravel một cách dễ dàng, linh hoạt như bẻ kẹo mà không sợ sâu răng.

Để làm gì ư? À, câu hỏi hay đấy! Anh em cứ nghĩ mà xem, trong một hệ thống thực tế:

  • Admin có thể làm mọi thứ: tạo, sửa, xóa bài viết, quản lý người dùng, xem báo cáo doanh thu.
  • Editor chỉ được phép tạo và sửa bài viết, nhưng không được xóa hoặc quản lý người dùng.
  • Viewer chỉ được đọc bài viết, không được phép làm gì khác.

Nếu anh em tự code hết mấy cái logic kiểm tra quyền này, đảm bảo project sẽ biến thành một đống spaghetti code rối nùi, khó bảo trì, và dễ sinh lỗi hơn cả việc code trong lúc buồn ngủ. Spatie Permissions sinh ra để giải quyết nỗi đau đó. Nó cung cấp một API cực kỳ trực quan để:

  1. Định nghĩa quyền hạn: Ai được làm gì (ví dụ: edit posts, delete users).
  2. Định nghĩa vai trò: Tập hợp các quyền hạn thành một vai trò (ví dụ: admin có quyền edit posts, delete users, publish articles).
  3. Gán vai trò/quyền hạn cho người dùng: User A là admin, User B là editor.
  4. Kiểm tra quyền hạn: Dễ dàng hỏi "User này có quyền edit posts không?" ở bất cứ đâu trong code của anh em.

Nói cách khác, nó là người gác cổng thông minh của tòa nhà ứng dụng, chỉ cho phép những ai có “thẻ ra vào” phù hợp mới được đi qua những khu vực nhất định. Quá tiện lợi, phải không?

Illustration

Bắt tay vào cài đặt và sử dụng (Code Ví Dụ)

Được rồi, lý thuyết sáo rỗng đủ rồi. Giờ chúng ta xắn tay áo lên và cùng Creyt xem nó hoạt động thế nào trên thực tế nhé!

Bước 1: Cài đặt gói qua Composer

composer require spatie/laravel-permission

Bước 2: Publish Migration và chạy Migration

Sau khi cài đặt, chúng ta cần publish các file migration của gói để tạo bảng roles, permissions và các bảng trung gian trong database.

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="permission-migrations"
php artisan migrate

Các bảng roles, permissions, model_has_roles, model_has_permissions, role_has_permissions sẽ được tạo ra. Chuẩn chỉ như sách giáo khoa.

Bước 3: Thêm Trait HasRoles vào User Model

Đây là bước quan trọng để model User của anh em có thể "hiểu" được các khái niệm về vai trò và quyền hạn.

// app/Models/User.php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles; // <-- Đừng quên dòng này!

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, HasRoles; // <-- Và thêm vào đây!

    // ... các thuộc tính và phương thức khác
}

Bước 4: Tạo Roles và Permissions (Seeders)

Thông thường, chúng ta sẽ tạo các vai trò và quyền hạn ban đầu thông qua seeders. Đây là cách "khai sinh" ra các thẻ bài quyền lực.

// database/seeders/RolesAndPermissionsSeeder.php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolesAndPermissionsSeeder extends Seeder
{
    public function run()
    {
        // Reset cached roles and permissions
        app()["cache"]->forget("spatie.permission.cache");

        // Tạo các quyền (Permissions)
        Permission::create(['name' => 'view dashboard']);
        Permission::create(['name' => 'edit articles']);
        Permission::create(['name' => 'delete articles']);
        Permission::create(['name' => 'publish articles']);
        Permission::create(['name' => 'manage users']);

        // Tạo các vai trò (Roles) và gán quyền
        $roleAdmin = Role::create(['name' => 'admin']);
        $roleAdmin->givePermissionTo(Permission::all()); // Admin có tất cả quyền

        $roleEditor = Role::create(['name' => 'editor']);
        $roleEditor->givePermissionTo(['edit articles', 'publish articles', 'view dashboard']);

        $roleViewer = Role::create(['name' => 'viewer']);
        $roleViewer->givePermissionTo(['view dashboard']);

        // Gán vai trò cho người dùng (ví dụ: người dùng đầu tiên là admin)
        $user = \App\Models\User::find(1); // Giả sử có user với ID 1
        if ($user) {
            $user->assignRole('admin');
        }

        $user2 = \App\Models\User::find(2); // User thứ hai là editor
        if ($user2) {
            $user2->assignRole('editor');
        }
    }
}

Sau đó, chạy seeder:

php artisan db:seed --class=RolesAndPermissionsSeeder

Bước 5: Kiểm tra quyền hạn

Đây là lúc chúng ta hỏi "Người này có được phép không?" ở các vị trí khác nhau trong ứng dụng.

a. Trong Controller / Logic PHP

// Ví dụ trong một controller

use Illuminate\Http\Request;
use App\Models\User;

class ArticleController extends Controller
{
    public function edit(Request $request, $articleId)
    {
        // Cách 1: Kiểm tra quyền trực tiếp
        if (!auth()->user()->can('edit articles')) {
            abort(403, 'Bạn không có quyền sửa bài viết này!');
        }

        // Cách 2: Kiểm tra vai trò
        if (auth()->user()->hasRole('admin')) {
            // Admin thì làm gì cũng được
        }

        // Cách 3: Kiểm tra nhiều quyền/vai trò
        if (auth()->user()->hasAnyPermission(['edit articles', 'delete articles'])) {
            // Có quyền sửa hoặc xóa
        }
        if (auth()->user()->hasAnyRole(['admin', 'editor'])) {
            // Là admin hoặc editor
        }

        // ... logic sửa bài viết
    }
}

b. Trong Blade Templates (View)

Spatie cung cấp các directive Blade cực kỳ tiện lợi để ẩn/hiện nội dung dựa trên quyền hạn hoặc vai trò.

@role('admin')
    <p>Chào mừng Admin! Bạn có thể làm mọi thứ.</p>
    <a href="/admin/users">Quản lý người dùng</a>
@endrole

@hasrole('editor')
    <p>Chào mừng Editor! Bạn có thể chỉnh sửa và xuất bản bài viết.</p>
@endhasrole

@can('edit articles')
    <button>Sửa bài viết này</button>
@else
    <button disabled>Không có quyền sửa</button>
@endcan

@hasanyrole(['admin', 'editor'])
    <p>Bạn là Admin hoặc Editor. Truy cập các tính năng nâng cao!</p>
@endhasanyrole

@unlessrole('viewer')
    <p>Bạn không phải là người xem. Bạn có quyền làm nhiều hơn!</p>
@endunlessrole

c. Với Middleware (Routes)

Để bảo vệ toàn bộ route hoặc nhóm route, anh em có thể dùng middleware.

// routes/web.php

Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        return view('dashboard');
    })->middleware(['permission:view dashboard']);

    Route::prefix('articles')->group(function () {
        Route::get('/', [ArticleController::class, 'index']);
        Route::get('/create', [ArticleController::class, 'create'])->middleware(['permission:edit articles']);
        Route::post('/', [ArticleController::class, 'store'])->middleware(['permission:edit articles']);
        Route::get('/{article}/edit', [ArticleController::class, 'edit'])->middleware(['permission:edit articles']);
        Route::put('/{article}', [ArticleController::class, 'update'])->middleware(['permission:edit articles']);
        Route::delete('/{article}', [ArticleController::class, 'destroy'])->middleware(['permission:delete articles']);
    });

    // Hoặc bảo vệ toàn bộ nhóm route bằng vai trò
    Route::prefix('admin')->middleware(['role:admin'])->group(function () {
        Route::get('/users', [AdminUserController::class, 'index']);
        // ... các route chỉ dành cho admin
    });
});

Mẹo và Best Practices từ Creyt

  1. Quyền hạn là "gốc rễ", Vai trò là "chùm": Luôn định nghĩa các quyền hạn thật chi tiết (ví dụ: create post, edit post, delete post). Sau đó, nhóm chúng lại thành các vai trò. Vai trò chỉ là một cách tiện lợi để gán một bộ quyền cho người dùng. Đừng bao giờ gán quyền trực tiếp cho người dùng nếu không thực sự cần thiết, sẽ rất khó quản lý về sau.
  2. Sử dụng Seeders một cách thông minh: Dùng seeders để khởi tạo các vai trò và quyền hạn mặc định trong môi trường phát triển và sản xuất. Điều này giúp đảm bảo tính nhất quán và dễ dàng triển khai.
  3. Tận dụng Caching: Spatie Permissions có hỗ trợ cache để tăng hiệu suất. Đảm bảo cache được bật và cấu hình đúng cách (mặc định là bật). Nếu anh em thay đổi quyền/vai trò trong quá trình chạy ứng dụng, đừng quên chạy php artisan permission:cache-reset để xóa cache.
  4. Tên quyền rõ ràng: Đặt tên quyền theo định dạng verb-noun (ví dụ: view-dashboard, create-users, delete-products). Điều này giúp dễ đọc, dễ hiểu và dễ quản lý.
  5. Nguyên tắc đặc quyền tối thiểu (Principle of Least Privilege): Luôn cấp cho người dùng ít quyền nhất cần thiết để họ thực hiện công việc của mình. Tránh việc cấp quyền admin một cách bừa bãi. Đây là nguyên tắc vàng trong bảo mật!
  6. Giao diện quản lý: Trong các ứng dụng lớn, anh em nên xây dựng một giao diện quản lý (admin panel) để admin có thể dễ dàng gán vai trò và quyền hạn cho người dùng mà không cần động vào code. Đây là bước nâng cao nhưng cực kỳ đáng giá.

Ứng dụng thực tế

Anh em có thấy các hệ thống lớn như WordPress, Joomla, hay bất kỳ hệ thống quản trị nội dung (CMS) nào không? Hay các nền tảng e-commerce như Magento, Shopify (ở khía cạnh quản lý nhân viên/người bán)? Hoặc các ứng dụng SaaS (Software as a Service) với các gói dịch vụ khác nhau (Basic, Premium, Enterprise) mà mỗi gói lại mở khóa các tính năng riêng biệt?

Tất cả chúng đều sử dụng một hệ thống phân quyền tương tự như Spatie Permissions. Ví dụ:

  • Website tin tức: Phân quyền Author (viết bài), Editor (duyệt, sửa, xuất bản), Moderator (kiểm duyệt bình luận), Admin (quản lý tất cả).
  • Hệ thống quản lý dự án: Project Manager (tạo, giao task, xem báo cáo), Developer (xem task, cập nhật trạng thái), Client (xem tiến độ).
  • Nền tảng học trực tuyến: Student (học bài, làm bài tập), Instructor (tạo khóa học, chấm bài), Admin (quản lý khóa học, người dùng).

Spatie Permissions chính là "xương sống" giúp các hệ thống này vận hành trơn tru, an toàn và có khả năng mở rộng mạnh mẽ. Nó giúp anh em tránh được những cơn đau đầu khi ứng dụng ngày càng phình to và đòi hỏi sự kiểm soát quyền hạn tinh vi hơn.

Đó, anh em thấy không? Một gói nhỏ bé nhưng lại có võ công thâm hậu, giúp chúng ta xây dựng những hệ thống vững chắc như tường thành. Hãy thực hành ngay để biến lý thuyết thành kỹ năng thực chiến nhé! Hẹn gặp lại trong bài học tiếp theo!

Thuộc Series: Lavarel

Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!