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:
-
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ànhAllowedở các tầng thấp hơn (Component, Category, Article) hoặc ở nhóm con. -
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ó.
-
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
Allowednào ở cấp dưới có thể ghi đè lại lệnhDeniedở cấp trên. -
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ứngDenied), thì lệnhDeniedluô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):
-
Tạo User Group: Vào
Users -> Groups, tạo nhómBan Biên Tập CNTTcó Group Parent làManager(hoặc tạo dướiRegisterednế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. -
Cấp quyền vào Admin (Tầng 1 - Global): Vào
System -> Global Configuration -> Permissions, chọn nhómBan 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).
- Đổi Administrator Login (
-
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ómBan 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!).
- Đổi Access Administration Interface (
-
Cấp quyền thao tác trên đúng Danh mục (Tầng 3 - Category): Mở danh mục
Khoa CNTT-> TabPermissions, chọn nhómBan Biên Tập CNTT:- Đổi Create, Edit, Edit State, Delete thành Allowed.
-
Đưa vào Access Level
Special: VàoUsers -> Access Levels -> Special, tích chọn thêm nhómBan Biên Tập CNTT(vì menu quản trị Backend mặc định yêu cầu Viewing Access Level làSpecialmớ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 Component Category 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ớiparent_id,lft,rgt,level). -
Tên định danh (
name) trong bảng#__assetstuâ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ủaroot.1). -
com_content.category.8: Danh mục có ID = 8 (Con củacom_content). -
com_content.article.42: Bài viết có ID = 42 (Con củacom_content.category.8).
-
-
Cột
rulestrong#__assetslư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,1là Allowed,0là 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 Component Category 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