Back to blog

Yii2 Authentication & Authorization: RBAC & AccessControl

yii2phpauthenticationauthorizationbackend
Yii2 Authentication & Authorization: RBAC & AccessControl

Phase 3 cho bạn task manager chạy với database thật. Ai cũng có thể tạo, sửa, xóa bất kỳ task nào. Đó là vấn đề. Ở production, bạn cần trả lời hai câu hỏi cho mỗi request:

  1. Authentication — Bạn là ai? (login, session, identity)
  2. Authorization — Bạn được phép làm gì? (roles, permissions, rules)

Yii2 có hệ thống built-in hoàn chỉnh cho cả hai. Không cần third-party packages hay tự quản lý session. Framework cung cấp IdentityInterface cho authentication, AccessControl cho permission gates đơn giản, và RBAC (Role-Based Access Control) component đầy đủ với database storage cho phân quyền phức tạp.

Cuối bài này, task manager sẽ có đăng ký user, login/logout, access rules ở controller level, và hệ thống RBAC hoàn chỉnh — admin quản lý tất cả task còn user thường chỉ quản lý task của mình.

Sẽ Xây Gì

✅ Đăng ký user với password hashing
✅ Login/logout với session-based authentication
✅ AccessControl behavior bảo vệ controller actions
✅ Database-backed RBAC với roles và permissions
✅ Custom RBAC rules cho kiểm tra "own resource"
✅ Phân quyền admin vs user thường


1. User Component

Mọi Yii2 app đều có user application component quản lý authentication state. Cấu hình trong config/web.php:

// config/web.php
'components' => [
    'user' => [
        'identityClass' => 'app\models\User',
        'enableAutoLogin' => true,
        'loginUrl' => ['site/login'],
    ],
],
PropertyMục đích
identityClassModel class implement IdentityInterface
enableAutoLoginHỗ trợ remember-me cookie
loginUrlRedirect user chưa login đến đâu

user component dùng được ở mọi nơi qua Yii::$app->user. Các method chính:

Yii::$app->user->isGuest;      // true nếu chưa login
Yii::$app->user->id;            // ID user hiện tại
Yii::$app->user->identity;      // instance User model hiện tại
Yii::$app->user->login($user);  // bắt đầu session
Yii::$app->user->logout();      // hủy session

2. IdentityInterface

Model User phải implement yii\web\IdentityInterface. Interface này có 5 method mà Yii2 gọi trong quá trình authentication:

// models/User.php
namespace app\models;
 
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
 
class User extends ActiveRecord implements IdentityInterface
{
    public static function tableName(): string
    {
        return 'users';
    }
 
    // --- Các method IdentityInterface ---
 
    /**
     * Tìm user theo primary key (session dùng để reload identity)
     */
    public static function findIdentity($id): ?self
    {
        return static::findOne($id);
    }
 
    /**
     * Tìm user theo access token (dùng cho stateless/API auth)
     */
    public static function findIdentityByAccessToken($token, $type = null): ?self
    {
        return static::findOne(['access_token' => $token]);
    }
 
    /**
     * Trả về giá trị primary key
     */
    public function getId(): int
    {
        return $this->id;
    }
 
    /**
     * Trả về key cho cookie-based login validation
     */
    public function getAuthKey(): string
    {
        return $this->auth_key;
    }
 
    /**
     * Validate auth key (so sánh stored vs provided)
     */
    public function validateAuthKey($authKey): bool
    {
        return $this->auth_key === $authKey;
    }
}

Migration Bảng Users

Tạo migration cho bảng users nếu chưa có:

php yii migrate/create create_users_table
public function safeUp(): void
{
    $this->createTable('users', [
        'id'          => $this->primaryKey(),
        'username'    => $this->string(50)->notNull()->unique(),
        'email'       => $this->string(255)->notNull()->unique(),
        'password_hash' => $this->string(255)->notNull(),
        'auth_key'    => $this->string(32)->notNull(),
        'access_token' => $this->string(255)->unique(),
        'status'      => $this->smallInteger()->notNull()->defaultValue(10),
        'created_at'  => $this->dateTime()->notNull(),
        'updated_at'  => $this->dateTime()->notNull(),
    ]);
}

Chạy migration:

php yii migrate

3. Password Hashing

Không bao giờ lưu password dạng plain text. Yii2 wrap password_hash() và password_verify() của PHP trong security helper:

use Yii;
 
class User extends ActiveRecord implements IdentityInterface
{
    // ... Các method IdentityInterface ở trên ...
 
    /**
     * Hash và lưu password
     */
    public function setPassword(string $password): void
    {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }
 
    /**
     * Verify password với hash đã lưu
     */
    public function validatePassword(string $password): bool
    {
        return Yii::$app->security->validatePassword($password, $this->password_hash);
    }
 
    /**
     * Tạo random auth key cho cookie-based login
     */
    public function generateAuthKey(): void
    {
        $this->auth_key = Yii::$app->security->generateRandomString();
    }
}

generatePasswordHash() dùng bcrypt mặc định với cost factor 13 — đủ mạnh cho hầu hết app. Bạn có thể điều chỉnh cost:

Yii::$app->security->generatePasswordHash($password, 12); // cost = 12

4. Đăng Ký (Signup)

Tạo form model cho đăng ký:

// models/SignupForm.php
namespace app\models;
 
use yii\base\Model;
 
class SignupForm extends Model
{
    public string $username = '';
    public string $email = '';
    public string $password = '';
 
    public function rules(): array
    {
        return [
            ['username', 'required'],
            ['username', 'string', 'min' => 3, 'max' => 50],
            ['username', 'unique', 'targetClass' => User::class],
 
            ['email', 'required'],
            ['email', 'email'],
            ['email', 'unique', 'targetClass' => User::class],
 
            ['password', 'required'],
            ['password', 'string', 'min' => 8],
        ];
    }
 
    public function signup(): ?User
    {
        if (!$this->validate()) {
            return null;
        }
 
        $user = new User();
        $user->username = $this->username;
        $user->email = $this->email;
        $user->setPassword($this->password);
        $user->generateAuthKey();
        $user->created_at = date('Y-m-d H:i:s');
        $user->updated_at = date('Y-m-d H:i:s');
 
        return $user->save() ? $user : null;
    }
}

Signup Controller Action

// controllers/SiteController.php
public function actionSignup(): string|\yii\web\Response
{
    $model = new SignupForm();
 
    if ($model->load(Yii::$app->request->post()) && $model->signup()) {
        Yii::$app->session->setFlash('success', 'Tài khoản đã tạo. Hãy đăng nhập.');
        return $this->redirect(['site/login']);
    }
 
    return $this->render('signup', ['model' => $model]);
}

Signup View

<!-- views/site/signup.php -->
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
 
$this->title = 'Đăng Ký';
?>
 
<h1><?= Html::encode($this->title) ?></h1>
 
<?php $form = ActiveForm::begin(); ?>
 
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
 
<div class="form-group">
    <?= Html::submitButton('Đăng Ký', ['class' => 'btn btn-primary']) ?>
</div>
 
<?php ActiveForm::end(); ?>

5. Đăng Nhập (Login)

Tạo form model cho login:

// models/LoginForm.php
namespace app\models;
 
use Yii;
use yii\base\Model;
 
class LoginForm extends Model
{
    public string $username = '';
    public string $password = '';
    public bool $rememberMe = true;
 
    private ?User $_user = null;
 
    public function rules(): array
    {
        return [
            [['username', 'password'], 'required'],
            ['rememberMe', 'boolean'],
            ['password', 'validatePassword'],
        ];
    }
 
    /**
     * Custom validator — kiểm tra password với database
     */
    public function validatePassword(string $attribute): void
    {
        if (!$this->hasErrors()) {
            $user = $this->getUser();
            if (!$user || !$user->validatePassword($this->password)) {
                $this->addError($attribute, 'Sai tên đăng nhập hoặc mật khẩu.');
            }
        }
    }
 
    public function login(): bool
    {
        if ($this->validate()) {
            return Yii::$app->user->login(
                $this->getUser(),
                $this->rememberMe ? 3600 * 24 * 30 : 0  // 30 ngày
            );
        }
        return false;
    }
 
    protected function getUser(): ?User
    {
        if ($this->_user === null) {
            $this->_user = User::findOne(['username' => $this->username]);
        }
        return $this->_user;
    }
}

Login Controller Action

public function actionLogin(): string|\yii\web\Response
{
    if (!Yii::$app->user->isGuest) {
        return $this->goHome();
    }
 
    $model = new LoginForm();
 
    if ($model->load(Yii::$app->request->post()) && $model->login()) {
        return $this->goBack(); // redirect về trang đang truy cập
    }
 
    return $this->render('login', ['model' => $model]);
}
 
public function actionLogout(): \yii\web\Response
{
    Yii::$app->user->logout();
    return $this->goHome();
}

Login View

<!-- views/site/login.php -->
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
 
$this->title = 'Đăng Nhập';
?>
 
<h1><?= Html::encode($this->title) ?></h1>
 
<?php $form = ActiveForm::begin(); ?>
 
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= $form->field($model, 'rememberMe')->checkbox() ?>
 
<div class="form-group">
    <?= Html::submitButton('Đăng Nhập', ['class' => 'btn btn-primary']) ?>
</div>
 
<?php ActiveForm::end(); ?>

6. AccessControl Filter

AccessControl là behavior gắn vào controller. Nó kiểm tra access rules trước khi action nào chạy — không cần setup RBAC. Coi như bảo vệ ở cửa.

Cách Dùng Cơ Bản

// controllers/TaskController.php
use yii\filters\AccessControl;
 
public function behaviors(): array
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'rules' => [
                [
                    'actions' => ['index', 'view'],
                    'allow'   => true,
                    'roles'   => ['?'],  // guest xem được
                ],
                [
                    'actions' => ['create', 'update', 'delete'],
                    'allow'   => true,
                    'roles'   => ['@'],  // chỉ user đã login
                ],
            ],
        ],
    ];
}

Ký Hiệu Role

Ký hiệuÝ nghĩa
?Guest (chưa login)
@Authenticated (user đã login)
adminRBAC role tên "admin" (cần setup RBAC)

Các Property Của Rule

Mỗi rule trong mảng rules là yii\filters\AccessRule với các property:

PropertyTypeMục đích
actionsarrayAction ID mà rule áp dụng (rỗng = tất cả)
allowbooltrue cho phép, false từ chối
rolesarray?, @, hoặc tên role/permission RBAC
ipsarrayIP whitelist (ví dụ ['127.0.0.1'])
verbsarrayHTTP methods (ví dụ ['POST', 'DELETE'])
matchCallbackcallableLogic matching tùy chỉnh

AccessControl Nâng Cao

'access' => [
    'class' => AccessControl::class,
    'only' => ['create', 'update', 'delete'],  // chỉ check các action này
    'rules' => [
        [
            'allow' => true,
            'roles' => ['@'],
            'matchCallback' => function ($rule, $action) {
                // Chỉ cho phép trong giờ hành chính
                $hour = (int) date('H');
                return $hour >= 9 && $hour < 17;
            },
        ],
    ],
    'denyCallback' => function ($rule, $action) {
        throw new \yii\web\ForbiddenHttpException('Không được phép truy cập.');
    },
],

Kết Hợp Với VerbFilter

Thường dùng AccessControl cùng VerbFilter cho REST-style controllers:

use yii\filters\AccessControl;
use yii\filters\VerbFilter;
 
public function behaviors(): array
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'rules' => [
                ['actions' => ['index', 'view'], 'allow' => true, 'roles' => ['?']],
                ['actions' => ['create'], 'allow' => true, 'roles' => ['@']],
                ['actions' => ['update', 'delete'], 'allow' => true, 'roles' => ['admin']],
            ],
        ],
        'verbs' => [
            'class' => VerbFilter::class,
            'actions' => [
                'delete' => ['POST'],
            ],
        ],
    ];
}

7. Tổng Quan RBAC

AccessControl ổn cho các trường hợp đơn giản (guest vs đã login). Nhưng app thực tế cần phân quyền tinh hơn:

  • "Author chỉnh sửa được bài của mình, không phải của người khác"
  • "Moderator xóa được bất kỳ comment nào"
  • "Admin làm được mọi thứ"

Đây là lúc RBAC (Role-Based Access Control) vào cuộc. RBAC của Yii2 là cây gồm ba loại node:

Loại NodeMục đíchVí dụ
RoleNhóm permission có tênadmin, author, moderator
PermissionMột khả năng cụ thểcreateTask, updateTask, deleteTask
RuleĐiều kiện động kiểm tra lúc runtime"User này có phải author của task này không?"

Roles chứa permissions. Permissions có thể có rules. Users được gán roles.


8. Setup RBAC Với DbManager

Yii2 cung cấp hai RBAC manager:

ManagerLưu trữPhù hợp
PhpManagerPHP filesApp đơn giản, ít role
DbManagerDatabase tablesProduction apps, role động

Ta dùng DbManager — lựa chọn đúng cho bất kỳ app nào không trivial.

8.1 Cấu Hình AuthManager

// config/web.php (và config/console.php — cần cho migration!)
'components' => [
    'authManager' => [
        'class' => 'yii\rbac\DbManager',
    ],
],

Quan trọng: Thêm authManager vào config/console.php luôn — lệnh migration chạy trong console context.

8.2 Tạo RBAC Tables

Yii2 ship sẵn migration cho RBAC tables:

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

Lệnh này tạo 4 bảng:

BảngMục đích
auth_ruleCustom rules (PHP classes)
auth_itemRoles và permissions
auth_item_childQuan hệ cha-con (role → permission)
auth_assignmentGán user ↔ role

8.3 Khởi Tạo Roles Và Permissions

Tạo console command để setup RBAC hierarchy ban đầu:

// commands/RbacController.php
namespace app\commands;
 
use Yii;
use yii\console\Controller;
 
class RbacController extends Controller
{
    public function actionInit(): void
    {
        $auth = Yii::$app->authManager;
 
        // Xóa dữ liệu cũ
        $auth->removeAll();
 
        // --- Permissions ---
        $createTask = $auth->createPermission('createTask');
        $createTask->description = 'Tạo task mới';
        $auth->add($createTask);
 
        $viewTask = $auth->createPermission('viewTask');
        $viewTask->description = 'Xem tasks';
        $auth->add($viewTask);
 
        $updateOwnTask = $auth->createPermission('updateOwnTask');
        $updateOwnTask->description = 'Sửa task của mình';
        $auth->add($updateOwnTask);
 
        $updateAnyTask = $auth->createPermission('updateAnyTask');
        $updateAnyTask->description = 'Sửa bất kỳ task nào';
        $auth->add($updateAnyTask);
 
        $deleteOwnTask = $auth->createPermission('deleteOwnTask');
        $deleteOwnTask->description = 'Xóa task của mình';
        $auth->add($deleteOwnTask);
 
        $deleteAnyTask = $auth->createPermission('deleteAnyTask');
        $deleteAnyTask->description = 'Xóa bất kỳ task nào';
        $auth->add($deleteAnyTask);
 
        $manageUsers = $auth->createPermission('manageUsers');
        $manageUsers->description = 'Quản lý tài khoản user';
        $auth->add($manageUsers);
 
        // --- Rules ---
        $isAuthorRule = new \app\rbac\IsAuthorRule();
        $auth->add($isAuthorRule);
 
        // Gắn rule vào permission "own"
        $updateOwnTask->ruleName = $isAuthorRule->name;
        $auth->update('updateOwnTask', $updateOwnTask);
 
        $deleteOwnTask->ruleName = $isAuthorRule->name;
        $auth->update('deleteOwnTask', $deleteOwnTask);
 
        // --- Roles ---
 
        // Role Author
        $author = $auth->createRole('author');
        $author->description = 'User thường, quản lý task của mình';
        $auth->add($author);
        $auth->addChild($author, $viewTask);
        $auth->addChild($author, $createTask);
        $auth->addChild($author, $updateOwnTask);
        $auth->addChild($author, $deleteOwnTask);
 
        // Role Admin (kế thừa tất cả permission của author + thêm)
        $admin = $auth->createRole('admin');
        $admin->description = 'Administrator với full access';
        $auth->add($admin);
        $auth->addChild($admin, $author);        // kế thừa author permissions
        $auth->addChild($admin, $updateAnyTask);
        $auth->addChild($admin, $deleteAnyTask);
        $auth->addChild($admin, $manageUsers);
 
        echo "RBAC hierarchy đã tạo xong.\n";
    }
}

Chạy:

php yii rbac/init

8.4 Gán Role Cho Users

Sau khi đăng ký, gán role mặc định:

// Trong SignupForm::signup() sau $user->save()
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->id);

Để nâng user lên admin:

$auth = Yii::$app->authManager;
$adminRole = $auth->getRole('admin');
$auth->assign($adminRole, $userId);

9. Viết Custom Rules

Rules là PHP classes đánh giá điều kiện động lúc runtime. IsAuthorRule kiểm tra user hiện tại có phải người tạo resource không:

// rbac/IsAuthorRule.php
namespace app\rbac;
 
use yii\rbac\Rule;
 
class IsAuthorRule extends Rule
{
    public $name = 'isAuthor';
 
    /**
     * @param int|string $userId   ID user
     * @param \yii\rbac\Item $item Role hoặc permission gắn rule này
     * @param array $params        Params truyền vào can()
     */
    public function execute($userId, $item, $params): bool
    {
        if (!isset($params['task'])) {
            return false;
        }
        return $params['task']->user_id == $userId;
    }
}

Dùng Rule Trong Controllers

// controllers/TaskController.php
public function actionUpdate(int $id): string|\yii\web\Response
{
    $task = Task::findOne($id);
    if ($task === null) {
        throw new \yii\web\NotFoundHttpException('Không tìm thấy task.');
    }
 
    // Kiểm tra RBAC: user này có quyền update TASK NÀY không?
    if (!Yii::$app->user->can('updateOwnTask', ['task' => $task])
        && !Yii::$app->user->can('updateAnyTask')) {
        throw new \yii\web\ForbiddenHttpException('Bạn không có quyền sửa task này.');
    }
 
    if ($task->load(Yii::$app->request->post()) && $task->save()) {
        return $this->redirect(['view', 'id' => $task->id]);
    }
 
    return $this->render('update', ['model' => $task]);
}

Method can():

Yii::$app->user->can('permissionName');                    // kiểm tra đơn giản
Yii::$app->user->can('updateOwnTask', ['task' => $task]); // với params cho rule

Khi gọi can('updateOwnTask', ['task' => $task]):

  1. RBAC tìm permission updateOwnTask
  2. Thấy có ruleName = 'isAuthor'
  3. Khởi tạo IsAuthorRule và gọi execute()
  4. execute() so sánh $task->user_id với user ID hiện tại
  5. Trả về true chỉ khi user là chủ task

10. Bảo Vệ TaskController

Gộp tất cả lại. Đây là TaskController đầy đủ với cả AccessControl và RBAC checks:

// controllers/TaskController.php
namespace app\controllers;
 
use Yii;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\web\ForbiddenHttpException;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use app\models\Task;
 
class TaskController extends Controller
{
    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    // Ai cũng xem được
                    ['actions' => ['index', 'view'], 'allow' => true, 'roles' => ['?', '@']],
                    // Chỉ user đã login mới tạo/sửa/xóa
                    ['actions' => ['create', 'update', 'delete'], 'allow' => true, 'roles' => ['@']],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }
 
    public function actionIndex(): string
    {
        $tasks = Task::find()
            ->with('user')
            ->orderBy(['created_at' => SORT_DESC])
            ->all();
 
        return $this->render('index', ['tasks' => $tasks]);
    }
 
    public function actionView(int $id): string
    {
        return $this->render('view', ['model' => $this->findModel($id)]);
    }
 
    public function actionCreate(): string|\yii\web\Response
    {
        if (!Yii::$app->user->can('createTask')) {
            throw new ForbiddenHttpException('Bạn không có quyền tạo task.');
        }
 
        $model = new Task();
        $model->user_id = Yii::$app->user->id;
 
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Yii::$app->session->setFlash('success', 'Đã tạo task.');
            return $this->redirect(['view', 'id' => $model->id]);
        }
 
        return $this->render('create', ['model' => $model]);
    }
 
    public function actionUpdate(int $id): string|\yii\web\Response
    {
        $model = $this->findModel($id);
 
        // RBAC: kiểm tra updateOwnTask (có rule) HOẶC updateAnyTask
        if (!Yii::$app->user->can('updateOwnTask', ['task' => $model])
            && !Yii::$app->user->can('updateAnyTask')) {
            throw new ForbiddenHttpException('Bạn không có quyền sửa task này.');
        }
 
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Yii::$app->session->setFlash('success', 'Đã cập nhật task.');
            return $this->redirect(['view', 'id' => $model->id]);
        }
 
        return $this->render('update', ['model' => $model]);
    }
 
    public function actionDelete(int $id): \yii\web\Response
    {
        $model = $this->findModel($id);
 
        if (!Yii::$app->user->can('deleteOwnTask', ['task' => $model])
            && !Yii::$app->user->can('deleteAnyTask')) {
            throw new ForbiddenHttpException('Bạn không có quyền xóa task này.');
        }
 
        $model->delete();
        Yii::$app->session->setFlash('success', 'Đã xóa task.');
 
        return $this->redirect(['index']);
    }
 
    protected function findModel(int $id): Task
    {
        $model = Task::findOne($id);
        if ($model === null) {
            throw new NotFoundHttpException('Không tìm thấy task.');
        }
        return $model;
    }
}

Pattern:

  1. AccessControl là cổng đầu tiên — bạn đã login chưa?
  2. RBAC checks bên trong action là cổng thứ hai — bạn có quyền đúng cho resource cụ thể này không?

11. Hiện/Ẩn UI Elements

Trong views, dùng can() để hiện/ẩn nút dựa trên permission:

<!-- views/task/view.php -->
<?php if (Yii::$app->user->can('updateOwnTask', ['task' => $model])
    || Yii::$app->user->can('updateAnyTask')): ?>
    <?= Html::a('Sửa', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
<?php endif; ?>
 
<?php if (Yii::$app->user->can('deleteOwnTask', ['task' => $model])
    || Yii::$app->user->can('deleteAnyTask')): ?>
    <?= Html::a('Xóa', ['delete', 'id' => $model->id], [
        'class' => 'btn btn-danger',
        'data' => [
            'confirm' => 'Bạn chắc chắn muốn xóa task này?',
            'method' => 'post',
        ],
    ]) ?>
<?php endif; ?>

Cho navigation items:

// views/layouts/main.php
$menuItems = [
    ['label' => 'Tasks', 'url' => ['/task/index']],
];
 
if (Yii::$app->user->can('manageUsers')) {
    $menuItems[] = ['label' => 'Users', 'url' => ['/user/index']];
}
 
if (Yii::$app->user->isGuest) {
    $menuItems[] = ['label' => 'Đăng Nhập', 'url' => ['/site/login']];
    $menuItems[] = ['label' => 'Đăng Ký', 'url' => ['/site/signup']];
} else {
    $menuItems[] = ['label' => 'Đăng Xuất (' . Yii::$app->user->identity->username . ')',
        'url' => ['/site/logout'],
        'linkOptions' => ['data-method' => 'post']
    ];
}

12. Sơ Đồ RBAC Hierarchy

Đây là cây permission hoàn chỉnh cho task manager:

Khi can() được gọi, Yii2 duyệt cây:

  1. Tìm role đã gán cho user (ví dụ author)
  2. Duyệt tất cả child permissions đệ quy
  3. Nếu permission có rule, thực thi rule đó
  4. Trả về true chỉ khi permission tồn tại VÀ rule pass

Vì admin có author là child, admin tự động kế thừa tất cả permission của author — không cần lặp lại.


13. Các Pattern Thường Dùng

Kiểm Tra Nhiều Permissions

// Helper method trong User model
public function canAny(array $permissions, array $params = []): bool
{
    foreach ($permissions as $permission) {
        if (Yii::$app->user->can($permission, $params)) {
            return true;
        }
    }
    return false;
}

Default Role Cho User Mới

Thay vì gán trong signup, dùng defaultRoles:

// config/web.php
'authManager' => [
    'class' => 'yii\rbac\DbManager',
    'defaultRoles' => ['author'],
],

Mọi user đã login sẽ là author mà không cần row auth_assignment. Hữu ích khi chỉ có một default role.

Thu Hồi Và Gán Lại Role

$auth = Yii::$app->authManager;
 
// Thu hồi role cụ thể
$role = $auth->getRole('author');
$auth->revoke($role, $userId);
 
// Thu hồi tất cả roles
$auth->revokeAll($userId);
 
// Lấy tất cả roles của user
$roles = $auth->getRolesByUser($userId);
// Trả về: ['author' => Role object, ...]

Kiểm Tra Roles Trong Console Commands

RBAC hoạt động trong console context luôn — chỉ cần đảm bảo authManager có trong config/console.php:

// commands/SomeController.php
$auth = Yii::$app->authManager;
$admins = $auth->getUserIdsByRole('admin');
// Trả về mảng user ID có role admin

Tiếp Theo

Task manager giờ đã có lớp security hoàn chỉnh:

  • User đăng ký, login, và logout được
  • AccessControl canh gác controller actions (guest vs đã login)
  • RBAC cung cấp phân quyền chi tiết (author vs admin, own vs any)
  • Custom rules xử lý kiểm tra động (task này có phải của mình?)
  • UI elements hiện/ẩn dựa trên permission

Deep Dive → Forms, Validation & Data Input — xây dựng form phức tạp với nested models, file upload, AJAX validation, custom validators, và data formatting với hệ thống form mạnh mẽ của Yii2.

← Phase 3: Active Record & Database | → Tổng quan series Yii2

📬 Đăng ký nhận bản tin

Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.

Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.

💬 Comments

Đăng nhập để bình luận

Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.