+1

Phân Quyền Hệ Thống Với RBAC: Hiểu Chuẩn Tới Đáy & Những "Cú Lừa" Dev Mới Hay Mắc Phải

Chào anh em lại là mình đây. Hồi mới chập chững vào nghề, nhận task "làm chức năng login", mình mừng rỡ múa phím nhoáng cái là xong. Nhưng đời không là như mơ, vài bữa sau sếp vỗ vai: "Em ơi, giờ anh muốn thằng A chỉ được xem bài, thằng B được sửa bài nhưng không được xóa, còn anh thì làm được hết. Em xử lý nhé!!!"

Lúc đó, giải pháp "chữa cháy" của mình là thêm một cột is_admin hoặc cột role (1 là user, 2 là mod, 3 là admin) vào bảng Users. Sau đó, code ngập ngụa trong đốngif(user.role == 2 || user.role === 3). hệ quả là khi dự án phình to, code trở thành một mớ bòng bong không thể bảo trì.

Nếu bạn đang đi vào vết xe đổ đó, thì chào mừng bạn đến với RBAC (Role-Based Access Control) - "vị cứu tinh" của mọi hệ thống phân quyền. Hôm nay, mình sẽ bóc tách nó một cách thực dụng nhất, chuẩn phong cách anh em backend đi làm thực tế nhé.

1. RBAC Bản Chất Là Gì?

Thay vì cấp quyền lẻ tẻ cho từng người (thử tưởng tượng công ty đó có 10.000 nhân viên thì click mỏi tay), RBAC đưa ra một tư duy thông minh hơn: Đẻ ra cái "Ghế" (Role), gán quyền (Permission) cho cái Ghế đó, rồi mời người (User) ngồi vào Ghế

Ba trụ chính của RBAC:

  • User: Nguyễn Văn A, Trần Thị B
  • Role (Vai trò): Admin, Kế toán, Content, Chăm sóc khách hàng.
  • Permission (Quyền hạn): Xem báo cáo tài chính, tạo bài viết mới, xóa user, khóa bình luận.

Luồng chạy:

  1. tạo Role Content Creator.
  2. Gán các Permission [create_post, edit_post] cho Role này.
  3. Gán anh A vào Role Content Creator => Bùm! Anh A tự động có quyền tạo và sửa bài viết

2. Thiết Kế Database "Chuẩn Sách Giáo Khoa" Cho RBAC

Để hệ thống linh hoạt nhất (một User có nhiều Role, một Role có nhiều Permission), bạn cần thiết kế 5 bảng với quan hệ Nhiều - Nhiều (Many-to-Many).

  • Bảng users: Chứa thông tin tài khoản (id, username, password...).
  • Bảng roles: Chứa danh sách vai trò (id, name, description). Ví dụ:id: 1, name: 'Admin'.
  • Bảng permissions: Chứa danh sách quyền (id, name, code). Ví dụ: id: 1, code: 'delete_user'.
  • Bảng user_roles (Bảng trung gian): Nối usersroles. Cho biết ai đang giữ vai trò gì. (user_id, role_id).
  • Bảng role_permissions (Bảng trung gian): Nối rolespermissions. Cho biết vai trò nào có quyền gì. (role_id, permission_id).

Với bộ khung 5 bảng này, dự án của bạn có scale (mở rộng) thêm chục phòng ban, hàng trăm nhân viên thì database vẫn đứng vững rưng rưng không cần sửa đổi cấu trúc

3. Những "Cú Lừa" (Pitfalls) Chí Mạng Khi Triển Khai Thực Tế

Học lý thuyết thì êm ru, nhưng vác đi làm thực tế thì dev mới rất hay sập hố. Dưới đây là những "vết sẹo" mình đúc kết được:

Sai lầm #1: Hardcode check Role thay vì check Permission

Đây là lỗi phổ biến nhất. Anh em thường viết code thế này:

if (user.role_name === 'Admin' || user.role_name === 'Manager') { // cho phép xoá bài }

Tại sao sai? Lỡ ngày mai sếp bảo: "Cho thằng Content Leader quyền xoá bài nữa em", thế là bạn lại phải mò vào code sửa thành || user.role_name === 'Content Leader', sau đó deploy lại toàn bộ dự án. Rất nghiệp dư!

Cách làm chuẩn: Chỉ check Permission.

if (user.can('delete_post')) { // cho phép xoá bài }

Lúc này, bạn chỉ cần vào database (hoặc giao diện admin CMS), gán quyền delete_post cho Role Content Leader là xong. Code không cần sửa một dòng nào!

Sai lầm #2: Tin tưởng tuyệt đối vào Frontend

Nhiều bạn nghĩ rằng: "Mình ẩn cái nút 'Xoá' đi đối với User thường là an toàn rồi". Nhầm to! Hacker thừa sức mở Postman lên và bắn thẳng API DELETE /api/posts/1 vào Backend của bạn. Cách làm chuẩn: Frontend ẩn nút để tốt cho trải nghiệm người dùng (UX). Nhưng Backend (API) BẮT BUỘC phải có Middleware chặn cổng, kiểm tra lại xem người dùng gọi API đó có giữ Permission tương ứng không.

Sai lầm #3: Bóp chết hiệu năng (Performance) vì query database liên tục

Cứ mỗi lần user click vào một trang, bạn lại query 3-4 bảng (join từ user qua roles, tới permissions) để xem nó có quyền không. Với hệ thống lớn, việc này sẽ làm database quá tải (bottleneck) ngay lập tức. Cách làm chuẩn: Cache (bộ nhớ đệm) là chân ái! Ngay khi user đăng nhập thành công, hãy lấy toàn bộ Permission của họ gom thành một mảng, nhét vào Redis hoặc đưa thẳng vào JWT (JSON Web Token) payload. Cứ thế mà dùng, hệ thống sẽ chạy mượt như lụa.

Tóm lại

RBAC không khó, cái khó là anh em phải set up tư duy "Check Quyền (Permission) chứ không Check Ghế (Role)" ngay từ những dòng code đầu tiên. Đầu tư thiết kế database 5 bảng tử tế ban đầu sẽ cứu rỗi bạn khỏi hàng nghìn giờ fix bug và đập đi xây lại sau này.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí