Giới thiệu về zend-permissions-rbac
zend-permissions-rbac
là một công cụ nhẹ triển khai phân quyền RBAC (role - based access control) dựa vào các lớp chuẩn PHP là RecursiveIterator và RecursiveIteratorIterator.RBAC khác với ACL tập trung vào các role hơn là các resourece. Các khái niệm cần biết ở đây gồm:
- Một identity (định danh) có một hoặc nhiều Role.
- Một role yêu cầu quyền truy cập.
- Một permission được chuyển cho Role.
Mối quan hệ giữa identity và role, giữa role và permision là mối quan hệ Nhiều - Nhiều.
Để cài đặt zend-permisions-rbac dùng composer như sau:
composer require zendframework/zend-permissions-rbac
Lưu ý đọc phân quyền với ACL với Zend trước. Các mục sau đây cách tạo và sử dụng khá tương tự ACL.
Tạo Role
Sử dụng Zend\Permission\Rbac\Role và sau đó đưa vào bộ chứa RBAC bằng lệnh addRole()
. Các Role có tính kế thừa, nếu Role con có quyền mặc định Role cha sẽ có quyền.
Tạo Permission
Mỗi Role có thể có các Permission và có thể thiết lập trực tiếp role bằng cách lấy từ trình chứa RBAC và có sự kế thừa cha chon giữa các role.
Ví dụ:
<?php use Zend\Permissions\Rbac\Rbac; use Zend\Permissions\Rbac\Role; include "vendor/autoload.php"; //Tạo trình chứa Rbac $rbac = new Rbac(); //Tạo một role $member = new Role('manager'); //Thêm đối tượng Role vào rabc $rbac->addRole($member); $rbac->addRole('admin', 'manager' ); $rbac->addRole('moderator', 'admin'); $rbac->addRole('editor', 'admin'); $rbac->addRole('member', ['moderator', 'editor']); /** * Các quyền view.post */ $rbac->getRole('member')->addPermission("view.post"); $rbac->getRole('editor')->addPermission('edit.post'); $rbac->getRole('moderator')->addPermission('createforum'); $rbac->getRole('admin')->addPermission('ban.user'); $rbac->getRole('manager')->addPermission('turnoffwebsite'); function check($role, $permission) { global $rbac; echo "\t$permission:\t".($rbac->isGranted($role, $permission)?'ĐƯỢC PHÉP':'*'), PHP_EOL; } $roles = ['manager', 'admin', 'moderator', 'editor', 'member']; $permissions = ['view.post', 'edit.post', 'createforum', 'ban.user', 'turnoffwebsite']; echo "<pre>"; foreach ($roles as $role) { echo $role, PHP_EOL; foreach ($permissions as $permission) check($role, $permission); } echo "</pre>";
Chạy mã trên ra kết quả:
manager view.post: ĐƯỢC PHÉP edit.post: ĐƯỢC PHÉP createforum: ĐƯỢC PHÉP ban.user: ĐƯỢC PHÉP turnoffwebsite: ĐƯỢC PHÉP admin view.post: ĐƯỢC PHÉP edit.post: ĐƯỢC PHÉP createforum: ĐƯỢC PHÉP ban.user: ĐƯỢC PHÉP turnoffwebsite: * moderator view.post: ĐƯỢC PHÉP edit.post: * createforum: ĐƯỢC PHÉP ban.user: * turnoffwebsite: * editor view.post: ĐƯỢC PHÉP edit.post: ĐƯỢC PHÉP createforum: * ban.user: * turnoffwebsite: * member view.post: ĐƯỢC PHÉP edit.post: * createforum: * ban.user: * turnoffwebsite: *
Tương tự như Acl, bạn cũng có thể dùng Assert để kiểm tra quyền cập nhật theo thời gian chạy, ví dụ:
use Zend\Permissions\Rbac\AssertionInterface; use Zend\Permissions\Rbac\Rbac; class AssertUserIdMatches implements AssertionInterface { protected $userId; protected $article; public function __construct($userId) { $this->userId = $userId; } public function setArticle($article) { $this->article = $article; } public function assert(Rbac $rbac) { if (! $this->article) { return false; } return ($this->userId === $this->article->getUserId()); } } // User is assigned the foo role with id 5 // News article belongs to userId 5 // Jazz article belongs to userId 6 $rbac = new Rbac(); $user = $mySessionObject->getUser(); $news = $articleService->getArticle(5); $jazz = $articleService->getArticle(6); $rbac->addRole($user->getRole()); $rbac->getRole($user->getRole())->addPermission('edit.article'); $assertion = new AssertUserIdMatches($user->getId()); $assertion->setArticle($news); // true always - bad! if ($rbac->isGranted($user->getRole(), 'edit.article')) { // hacks another user's article } // true for user id 5, because he belongs to write group and user id matches if ($rbac->isGranted($user->getRole(), 'edit.article', $assertion)) { // edits his own article } $assertion->setArticle($jazz); // false for user id 5 if ($rbac->isGranted($user->getRole(), 'edit.article', $assertion)) { // can not edit another user's article }