0

Joomla Bài học 12: Làm chủ hệ thống phân quyền ACL (Access Control List) chi tiết đến từng Component và Bài viết

Nếu ở Bài học 11, chúng ta đã giải quyết xong bài toán "Ai được nhìn thấy gì?" thông qua Viewing Access Levels, thì trong Joomla Bài học 12 này, chúng ta sẽ chinh phục nửa còn lại — và cũng là phần quyền năng nhất của Joomla: "Ai được phép thực hiện hành động gì?" (Action Permissions).

Hệ thống ACL của Joomla 5 cho phép bạn kiểm soát quyền hạn chi tiết đến mức: cùng thuộc nhóm Biên tập viên, nhưng người ở ban Kinh tế chỉ được sửa bài trong danh mục Kinh tế, hoặc thậm chí chỉ được quyền sửa duy nhất một bài viết cụ thể mà không được đụng vào các bài khác.

1. 9 Hành động cốt lõi (Core Actions) trong Joomla ACL

Trong Joomla, mọi quyền thao tác đều được chuẩn hóa thành các hành động (Actions). Khi bạn mở tab Permissions ở bất kỳ đâu trong hệ thống, bạn sẽ bắt gặp các hành động cốt lõi sau:

Tên Action (Kỹ thuật) Tên hiển thị (UI) Ý nghĩa thực tế
core.login.site Site Login Quyền đăng nhập vào giao diện ngoài (Frontend).
core.login.admin Administrator Login Quyền đăng nhập vào trang quản trị (/administrator).
core.admin Super User / Configure ACL Quyền tối cao toàn hệ thống hoặc quyền cấu hình tab Options/Permissions của một Component.
core.manage Access Administration Interface Quyền được phép mở và truy cập vào giao diện của một Component trong trang quản trị.
core.create Create Quyền tạo mới dữ liệu (Bài viết, Danh mục, Module...).
core.delete Delete Quyền xóa vĩnh viễn dữ liệu khỏi thùng rác (Trash).
core.edit Edit Quyền chỉnh sửa mọi bản ghi (của cả người khác) trong phạm vi được cấp.
core.edit.state Edit State Quyền thay đổi trạng thái (Publish, Unpublish, Archive, Trash) hoặc chuyển bước Workflow.
core.edit.own Edit Own Quyền chỉ được sửa bài viết do chính mình tạo ra (dựa trên cột created_by trong DB).

2. Cơ chế Kế thừa 4 tầng (4-Tier Inheritance Hierarchy)

Điểm làm nên sự tinh vi của Joomla ACL là cơ chế thác nước (Cascading Inheritance) đi từ đỉnh hệ thống xuống từng bản ghi đơn lẻ, kết hợp với cây phân cấp User Groups (Nhóm con kế thừa quyền của nhóm cha):

Plaintext

[Tầng 1: Global Configuration] (Cấu hình toàn cục: System -> Global Configuration -> Permissions)
       │
       ▼  (Kế thừa xuống)
[Tầng 2: Component Options]    (Cấu hình từng ứng dụng: Ví dụ Content -> Articles -> Options -> Permissions)
       │
       ▼  (Kế thừa xuống)
[Tầng 3: Category (Nhiều cấp)] (Cấu hình từng danh mục cha -> danh mục con: Tab Permissions trong Category)
       │
       ▼  (Kế thừa xuống)
[Tầng 4: Single Item/Article]  (Cấu hình trên chính bài viết hoặc module cụ thể đó)

3. Quy tắc tính toán quyền hạn (Permission States & Conflict Resolution)

Tại mỗi tầng và cho mỗi User Group, bạn có thể chọn 1 trong 3 giá trị: Inherited (Kế thừa), Allowed (Cho phép), hoặc Denied (Từ chối). Hệ thống sẽ tự động tính toán và hiển thị kết quả cuối cùng ở cột Calculated Setting dựa trên 4 quy tắc bất di bất dịch sau:

  1. Not Allowed (Default): Nếu ở Tầng 1 (Global) một nhóm để là Inherited, hệ thống mặc định tính là Not Allowed (Không được phép), nhưng CÓ THỂ được bật lại thành Allowed ở các tầng thấp hơn (Component, Category, Article) hoặc ở nhóm con.

  2. Allowed (Cho phép): Cấp quyền thực thi hành động đó cho nhóm hiện tại và toàn bộ các nhóm con, các tầng bên dưới nó.

  3. Denied (Từ chối cứng - Hard Deny): Một khi bạn chọn Denied ở bất kỳ đâu, quyền đó sẽ bị khóa thành Not Allowed (Locked) cho toàn bộ các nhóm con và các tầng bên dưới. Không một cấu hình Allowed nào ở cấp dưới có thể ghi đè lại lệnh Denied ở cấp trên.

  4. Quy tắc đối kháng đa nhóm (Multi-Group Rule): Nếu một User thuộc 2 nhóm cùng lúc (Ví dụ: Nhóm A được Allowed, nhưng Nhóm B bị gán cứng Denied), thì lệnh Denied luôn luôn thắng!

Kinh nghiệm xương máu cho Admin & Dev: Tuyệt đối hạn chế dùng trạng thái Denied, trừ khi bạn muốn chặn vĩnh viễn một nhóm truy cập vào một khu vực nhạy cảm. Thay vào đó, hãy giữ mặc định là Inherited ở cấp trên (tương đương Soft Deny - Từ chối mềm), rồi chỉ bật Allowed ở đúng nhánh Category hoặc User Group bạn muốn cấp quyền.

4. Kịch bản thực hành: Phân quyền riêng biệt cho từng Phòng ban

Bài toán: Bạn xây dựng cổng thông tin trường Đại học có 2 khoa: Khoa CNTT và Khoa Kinh Tế. Yêu cầu nhân sự Khoa CNTT đăng nhập vào /administrator, chỉ thấy menu quản lý Bài viết và chỉ được thêm/sửa/xuất bản bài viết trong danh mục Khoa CNTT, tuyệt đối không được sửa bài của Khoa Kinh Tế.

Các bước thiết lập chuẩn xác (Mất 3 phút):

  1. Tạo User Group: Vào Users -> Groups, tạo nhóm Ban Biên Tập CNTT có Group Parent là Manager (hoặc tạo dưới Registered nếu muốn cấp quyền từ con số 0). Để an toàn và sạch nhất, hãy chọn Parent là Registered.

  2. Cấp quyền vào Admin (Tầng 1 - Global): Vào System -> Global Configuration -> Permissions, chọn nhóm Ban Biên Tập CNTT:

    • Đổi Administrator Login (core.login.admin) thành Allowed. (Giữ nguyên tất cả các quyền khác là Inherited).
  3. Cấp quyền mở giao diện Bài viết (Tầng 2 - Component): Vào Content -> Articles -> Options -> Permissions, chọn nhóm Ban Biên Tập CNTT:

    • Đổi Access Administration Interface (core.manage) thành Allowed. (Chưa cấp quyền Create/Edit ở đây vì nếu cấp ở đây họ sẽ sửa được bài của toàn bộ các khoa!).
  4. Cấp quyền thao tác trên đúng Danh mục (Tầng 3 - Category): Mở danh mục Khoa CNTT -> Tab Permissions, chọn nhóm Ban Biên Tập CNTT:

    • Đổi Create, Edit, Edit State, Delete thành Allowed.
  5. Đưa vào Access Level Special: Vào Users -> Access Levels -> Special, tích chọn thêm nhóm Ban Biên Tập CNTT (vì menu quản trị Backend mặc định yêu cầu Viewing Access Level là Special mới hiển thị thanh công cụ và menu).

5. Giải phẫu bảng #__assets và Code PHP kiểm tra ACL (Góc nhìn Backend)

Dưới góc độ kỹ thuật, tại sao Joomla có thể kế thừa quyền từ Global →\rightarrow Component →\rightarrow Category →\rightarrow Article nhanh đến vậy mà không cần join hàng chục bảng khác nhau?

Câu trả lời nằm ở bảng #__assets — trái tim thực sự của Joomla ACL:

  • Mọi Component, Category, Article, Module khi sinh ra đều tự động tạo một bản ghi tương ứng trong bảng #__assets (theo cấu trúc cây Nested Set với parent_id, lft, rgt, level).

  • Tên định danh (name) trong bảng #__assets tuân theo quy ước phân cấp rõ ràng:

    • root.1: Cấu hình Global Configuration.

    • com_content: Cấu hình Component Articles (Con của root.1).

    • com_content.category.8: Danh mục có ID = 8 (Con của com_content).

    • com_content.article.42: Bài viết có ID = 42 (Con của com_content.category.8).

  • Cột rules trong #__assets lưu chuỗi JSON chứa các thiết lập khác rỗng (Ví dụ: {"core.create":{"6":1},"core.delete":{"6":0}} trong đó "6" là ID của User Group, 1 là Allowed, 0 là Denied).

Cách kiểm tra quyền ACL bằng PHP trong Joomla 5:

Khi lập trình Component hoặc Plugin, bạn sử dụng phương thức $user->authorise($action, $assetName) để kiểm tra quyền:

PHP

use Joomla\CMS\Factory;

$app  = Factory::getApplication();
$user = $app->getIdentity();

// 1. Kiểm tra xem User có phải là Super Admin tối cao không
if ($user->authorise('core.admin')) {
    echo "Bạn là Super User!";
}

// 2. Kiểm tra quyền tạo bài viết mới trong toàn bộ com_content (Tầng Component)
if ($user->authorise('core.create', 'com_content')) {
    echo "Được phép tạo bài viết chung.";
}

// 3. Kiểm tra quyền tạo bài viết trong một Category cụ thể (ID = 8)
$categoryId = 8;
if ($user->authorise('core.create', 'com_content.category.' . $categoryId)) {
    echo "Được phép đăng bài vào danh mục số 8.";
}

// 4. Kiểm tra quyền sửa một Bài viết cụ thể (ID = 42) - Kết hợp cả core.edit và core.edit.own
$articleId       = 42;
$articleAuthorId = 105; // Giả sử lấy từ cột created_by của bài viết trong DB

$canEdit    = $user->authorise('core.edit', 'com_content.article.' . $articleId);
$canEditOwn = $user->authorise('core.edit.own', 'com_content.article.' . $articleId) 
              && ($articleAuthorId == $user->id);

if ($canEdit || $canEditOwn) {
    echo "Hợp lệ! Cho phép mở form chỉnh sửa bài viết số 42.";
} else {
    throw new \Joomla\CMS\Access\Exception\NotAllowed('Bạn không có quyền sửa bài viết này!', 403);
}

6. Tổng kết bài học

  • Nắm vững ý nghĩa của 9 Core Actions và cơ chế kế thừa 4 tầng (Global →\rightarrow Component →\rightarrow Category →\rightarrow Item).

  • Hiểu rõ quy tắc tính toán quyền hạn: Tại sao luôn ưu tiên dùng Inherited thay vì Denied để tránh khóa cứng cây kế thừa.

  • Hiểu kiến trúc bảng #__assets ở tầng Database và thành thạo hàm $user->authorise() trong PHP để bảo vệ logic ứng dụng.

Trong Bài học 13, chúng ta sẽ khám phá một niềm tự hào khác của Joomla so với các CMS khác: Xây dựng website đa ngôn ngữ (Multilingual) tích hợp sẵn trong Core không cần cài thêm bên thứ ba.


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í