Tiếp tục phần này như đã hứa, tại hạ sẽ giới thiệu với anh em đồng dev về phân quyền với RBAC trong Yii2 Framework. Cái gì thì cũng phải có trên có dưới thế nên trong phần mềm cũng vậy, cũng cần phải có quyền nọ quyền kia không thì loạn hết ứng dụng anh em ạ =)). Mặc dù các anh em đồng dev có thể làm chay mấy phần kiểu dạng phân quyền trong ứng dụng, nhưng nếu đã có hỗ trợ thì tội gì không dùng nhỉ.

RBAC là gì ?

RBAC hay Role Based Access Control là module được cung cấp để kiểm soát truy cập của người dùng dựa trên vai trò. Đây là một phương pháp có thể thay thế Điều khiển truy cập tùy quyền (discretionary access control - DAC) và Điều khiển truy cập bắt buộc (mandatory access control - MAC).

Yii triển khai RBAC theo mô hình NIST RBAC . Nó cung cấp chức năng RBAC thông qua thành phần ứng dụng authManager .Sử dụng RBAC liên quan đến hai phần công việc. Phần đầu tiên là xây dựng dữ liệu ủy quyền RBAC và phần thứ hai là sử dụng dữ liệu ủy quyền để thực hiện kiểm tra quyền truy cập ở những nơi cần thiết.

Một vai trò đại diện cho một tập hợp các quyền (ví dụ: tạo bài đăng, cập nhật bài đăng). Một vai trò có thể được chỉ định cho một hoặc nhiều người dùng. Để kiểm tra xem người dùng có quyền được chỉ định hay không.

Liên kết với mỗi vai trò hoặc quyền có thể có một rule . Rule đại diện cho một đoạn mã sẽ được thực thi trong quá trình kiểm tra quyền truy cập để xác định xem vai trò hoặc quyền tương ứng có áp dụng cho người dùng hiện tại hay không. Ví dụ: quyền "cập nhật bài đăng" có thể có rule kiểm tra xem người dùng hiện tại có phải là người tạo bài đăng hay không. Trong quá trình kiểm tra quyền truy cập, nếu người dùng KHÔNG phải là người tạo bài đăng, họ sẽ được coi là không có quyền "cập nhật bài đăng".

Cấu hình RBAC

Trước khi bắt đầu xác định việc ủy quyền và thực hiện kiểm tra quyền truy cập, các đồng dev cần định cấu hình thành phần ứng dụng authManager . Yii cung cấp hai loại trình quản lý ủy quyền: yii \ rbac \ PhpManager và yii \ rbac \ DbManager . PhpManager sử dụng tệp tập lệnh PHP để lưu trữ dữ liệu ủy quyền, trong khi DbManager lưu trữ dữ liệu ủy quyền trong cơ sở dữ liệu. Các đồng dev có thể cân nhắc sử dụng PhpManager nếu ứng dụng không yêu cầu quản lý vai trò và quyền cần tùy chỉnh được.

Sử dụng PhpManager

Đoạn mã sau cho biết cách đặt cấu hình authManager trong cấu hình ứng dụng bằng lớp yii \ rbac \ PhpManager, các đồng dev cài đặt trong common/config/main.php như sau:

return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\PhpManager',
        ],
        // ...
    ],
];

Các authManager bây giờ có thể được truy cập thông qua \Yii::$app->authManager.

Theo mặc định, yii \ rbac \ PhpManager lưu trữ dữ liệu RBAC bằng các tệp trong thư mục @app/rbac. Đảm bảo rằng thư mục và tất cả các tệp trong đó có thể ghi được.

 

Sử dụng DbManager

Đoạn mã sau đây cho thấy cách đặt cấu hình authManagertrong cấu hình ứng dụng bằng lớp yii \ rbac \ DbManager :

return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
            // uncomment if you want to cache RBAC items hierarchy
            // 'cache' => 'cache',
        ],
        // ...
    ],
];

DbManager sử dụng 4 bảng cơ sở dữ liệu để lưu trữ dữ liệu của nó:

  • itemTable : bảng lưu trữ các mục ủy quyền. Mặc định là "auth_item".
  • itemChildTable : bảng lưu trữ phân cấp mục ủy quyền. Mặc định là "auth_item_child".
  • assignmentTable : bảng lưu trữ các quyền được gán. Mặc định là "auth_assignment".
  • ruleTable : bảng lưu trữ các luật hay quy tắc. Mặc định là "auth_rule".

Trước khi có thể tiếp tục, các đồng dev cần tạo các bảng đó trong cơ sở dữ liệu. Để làm điều này, các đồng dev có thể sử dụng câu lệnh dưới đây để chạy các file migration trong rbac(Phần migration tại hạ sẽ có bài viết ngay sau phần này nhé laugh):

yii rbac

yii migrate --migrationPath=@yii/rbac/migrations

yii rbac

OK, vậy là là đã 4 bảng trong database rồi nhé

yii2 rbac

Tiếp tục để phân quyền qua RBAC, các đồng dev làm theo trình tự sau:

1. Đinh nghĩa các vai trò và các quyền cần thiết.

2. Thiết lập các mối quan hệ giữa quyền và vai trò.

3. Định nghĩa các quy tắc hay luật 

4. Liên kết các luật với vai trò và quyền

5. Gán vai trò cho người dùng

Ví dụ tại hạ có 2 vai trò là AdminAuthor, Admin sẽ có toàn quyền của Author và thêm quyền update bài viết và Author thì chỉ có quyền tạo bài viết. Tại hạ tiếp tục sử dụng migration để chạy migrate tạo ra các quyền và vai trò cần thiết như sau

- Đầu tiên sẽ tạo file migration bằng cách chạy lệnh sau trong command line:

./yii migrate/create init_rbac

Sau đó nhấn y để tạo

yii2 rbac

OK thành công, tiếp tục chạy câu lệnh migrate để thực thi chèn dữ liệu vào database

./yii migrate

yii2 rbac

Kiểm tra database đã có dữ liệu là được

yii2 rbac

Để gán vai trò cho user, tại hạ sẽ demo ở bước đăng ký trong hàm signup của frontend\models\SignupForm như sau:

public function signup()
{
    if ($this->validate()) {
        $user = new User();
        $user->username = $this->username;
        $user->email = $this->email;
        $user->setPassword($this->password);
        $user->generateAuthKey();
        $user->save(false);

        // the following three lines were added:
        $auth = \Yii::$app->authManager;
        $authorRole = $auth->getRole('author');
        $auth->assign($authorRole, $user->getId());

        return $user;
    }

    return null;
}

Như vậy các user mới đăng ký sẽ được gán cho vai trò là Author và chỉ có quyền đựợc tạo bài viết.

Để kiểm tra quyền truy cập thông qua dữ liệu đã có bên trên, tại hạ sẽ sử dụng \Yii::$app->user->can để check. Ví dụ, tại hạ muốn check xem user này có quyền sửa bài viết không

if (\Yii::$app->user->can('updatePost')) {
    // update post
}

Ngoài ra, còn sử dụng RBAC được trong AccessControl như sau:

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'rules' => [
                [
                    'allow' => true,
                    'actions' => ['create'],
                    'roles' => ['createPost'],
                ],
                [
                    'allow' => true,
                    'actions' => ['update'],
                    'roles' => ['updatePost'],
                ],
            ],
        ],
    ];
}

Với phần sử dụng PhpManager thì các đồng dev làm như sau:

- Đầu tiên các đồng dev tạo cho tại hạ 1 controller là RbacController trong console để tí chạy command cho phần RBAC

<?php
namespace console\controllers;

use Yii;
use yii\console\Controller;

class RbacController extends Controller
{
    public function actionInit()
    {
        $auth = Yii::$app->authManager;
        $auth->removeAll();
        
        // add "createPost" permission
        $createPost = $auth->createPermission('createPost');
        $createPost->description = 'Create a post';
        $auth->add($createPost);

        // add "updatePost" permission
        $updatePost = $auth->createPermission('updatePost');
        $updatePost->description = 'Update post';
        $auth->add($updatePost);

        // add "author" role and give this role the "createPost" permission
        $author = $auth->createRole('author');
        $auth->add($author);
        $auth->addChild($author, $createPost);

        // add "admin" role and give this role the "updatePost" permission
        // as well as the permissions of the "author" role
        $admin = $auth->createRole('admin');
        $auth->add($admin);
        $auth->addChild($admin, $updatePost);
        $auth->addChild($admin, $author);

        // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()
        // usually implemented in your User model.
        $auth->assign($author, 2);
        $auth->assign($admin, 1);
    }
}

Sau đó chạy command

./yii rbac/init

Tiếp tục trong thư mục console, tạo 1 thư mục rbac và tạo file console\rbac\UserGroupRule.php trong thư mục rbac vừa tạo

namespace console\rbac;

use Yii;
use yii\rbac\Rule;

/**
 * Checks if user group matches
 */
class UserGroupRule extends Rule
{
    public $name = 'userGroup';

    public function execute($user, $item, $params)
    {
        if (!Yii::$app->user->isGuest) {
            $group = Yii::$app->user->identity->group;
            if ($item->name === 'admin') {
                return $group == 1;
            } elseif ($item->name === 'author') {
                return $group == 1 || $group == 2;
            }
        }
        return false;
    }
}

Cuối cùng sửa lại config trong common/main.php như sau:

return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\PhpManager',
            'defaultRoles' => ['admin', 'author'],
        ],
        // ...
    ],
];

Và sử dụng Yii::$app->user->identity->group để kiểm tra, nếu là 1 thì là vai trò admin còn lại thì là vai trò group.

Tổng kết 

Bài viết chỉ nêu ra cách thức hoạt động phân quyền của RBAC trong 2 trường hơp sử dụng với dữ liệu và không sử dụng dữ liệu. Ngoài việc sử dụng RBAC ra các anh em đồng dev có thể tự build cho mình 1 hệ thống phân quyền riêng của mình để có thể sử dụng dễ dàng hơn. Bài viết còn nhiều thiếu sót mong anh em bỏ quá cho tại hạ laugh.