= Yii 2 Role Based Access Control = == Configuration == Enable RBAC in ''common/config/main.php'' (''app/config/console.php'' and ''app/config/test.php'' as well), by adding component ''authManager'' and assigning one of these authorization managers: ''PhpManager'' or ''DbManager''. === PhpManager === When using simple file based roles, enable ''PhpManager'': return [ 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'components' => [ ... 'authManager' => [ 'class' => 'yii\rbac\PhpManager', 'defaultRoles' => ['admin', 'editor', 'author', 'registered'], // Default roles // By default, yii\rbac\PhpManager stores RBAC data in files under @app/rbac/ directory. // Here, let us place them in @common/rbac/, and make sure dir is web writable. 'itemFile' => '@common/rbac/data/items.php', // Default path to items.php 'assignmentFile' => '@common/rbac/data/assignments.php', // Default path to assignments.php 'ruleFile' => '@common/rbac/data/rules.php', // Default path to rules.php ], ], ]; File ''@common/rbac/data/items.php'': [ 'type' => yii\rbac\Item::TYPE_PERMISSION, //2, 'description' => 'Create Users', ], 'updateUserProfile' => [ 'type' => yii\rbac\Item::TYPE_PERMISSION, //2, 'description' => 'Update User Profile', ], 'createContent' => [ 'type' => yii\rbac\Item::TYPE_PERMISSION, //2, 'description' => 'Create Content', ], 'updateContent' => [ 'type' => yii\rbac\Item::TYPE_PERMISSION, //2, 'description' => 'Update Content', ], 'updateOwnContent' => [ 'type' => yii\rbac\Item::TYPE_PERMISSION, //2, 'description' => 'Update own content', 'ruleName' => 'isAuthor', 'children' => [ 'updateContent', ], ], 'viewTechnicalManual' => [ 'type' => yii\rbac\Item::TYPE_PERMISSION, //2, 'description' => 'View Technical Manual', ], //--------------------------- // ROLES //--------------------------- 'registered' => [ 'type' => yii\rbac\Item::TYPE_ROLE, //1, 'ruleName' => 'userRole', ], 'module' => [ 'type' => yii\rbac\Item::TYPE_ROLE, //1, 'ruleName' => 'userRole', 'children' => [ 'registered', 'viewTechnicalManual', ], ], 'poweruser' => [ 'type' => yii\rbac\Item::TYPE_ROLE, //1, 'ruleName' => 'userRole', 'children' => [ 'module', ], ], 'author' => [ 'type' => yii\rbac\Item::TYPE_ROLE, //1, 'ruleName' => 'userRole', 'children' => [ 'poweruser', 'createContent', 'updateOwnContent', ], ], 'editor' => [ 'type' => yii\rbac\Item::TYPE_ROLE, //1, 'ruleName' => 'userRole', 'children' => [ 'author', 'updateUserProfile', 'updateContent', ], ], 'admin' => [ 'type' => yii\rbac\Item::TYPE_ROLE, //1, 'ruleName' => 'userRole', 'children' => [ 'editor', 'createUsers', 'updateContent', ], ], ]; File '''@common/rbac/data/assignments.php'': [ 'admin', ], 2 => [ 'registered', ], 1801 => [ 'registered', ], //... ]; File ''@common/rbac/data/rules.php'': 'O:24:"common\\rbac\\UserRoleRule":3:{s:4:"name";s:8:"userRole";s:9:"createdAt";N;s:9:"updatedAt";N;}', 'isAuthor' => 'O:22:"common\\rbac\\AuthorRule":3:{s:4:"name";s:8:"isAuthor";s:9:"createdAt";N;s:9:"updatedAt";N;}', ]; === DbManager === When using enterprise level DB based roles, enable ''DbManager'': return [ 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'components' => [ ... 'authManager' => [ 'class' => 'yii\rbac\DbManager', // NOTE: DbManager requires to migrate first: // $ yii migrate --migrationPath=@yii/rbac/migrations ], ], ]; DbManager requires to migrate first. Execute the following command at the yii console: $ yii migrate --migrationPath=@yii/rbac/migrations == Roles == Define user roles in ''[app]\common\models\User.php'' ... class User extends ActiveRecord implements IdentityInterface { // Roles const ROLE_ADMIN = 1; // Super user const ROLE_MANAGER = 2; // Create/update content, edit user profiles const ROLE_EDITOR = 3; // Create/update content const ROLE_AUTHOR = 4; // Create content, update own content only const ROLE_POWERUSER = 5; // Access to company content (not for public) const ROLE_USER = 10; // Basic site use. Same as ROLE_REGISTERED const ROLE_REGISTERED = 10; // Basic site use. Same as ROLE_USER //... public function rules() { return [ ['role', 'default', 'value' => self::ROLE_REGISTERED], ['role', 'in', 'range' => [ self::ROLE_ADMIN, self::ROLE_MANAGER, self::ROLE_EDITOR, self::ROLE_AUTHOR, self::ROLE_POWERUSER, self::ROLE_REGISTERED, ]], //... ]; } /** * @inheritdoc */ public function getRole() { return $this->role; //return Yii::$app->authManager->getRolesByUser(Yii::$app->user->getId()); // requires authManager //return Yii::$app->authManager->getRolesByUser(User::findByUsername($this->username)->getId()); // requires authManager } public static function getRoleLabel($aRole) { $roles = self::getRoles(); return $roles[$aRole]; } public static function getRoles() { return [ self::ROLE_ADMIN => 'admin', self::ROLE_MANAGER => 'manager', self::ROLE_EDITOR => 'editor', self::ROLE_AUTHOR => 'author', self::ROLE_USER => 'user', self::ROLE_POWERUSER => 'poweruser', self::ROLE_REGISTERED => 'registered', ]; } } == Status == Define user status in ''[app]\common\models\User.php'' ... class User extends ActiveRecord implements IdentityInterface { // Status const STATUS_BANNED = -2; const STATUS_DELETED = -1; const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1; //... public function rules() { return [ ['status', 'default', 'value' => self::STATUS_INACTIVE], ['status', 'in', 'range' => [ self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_DELETED, self::STATUS_BANNED, ]], //... ]; } public static function getStatusLabel($aStatus, $is_html=true) { $statuses = self::getStatuses(); if ($is_html) { switch($aStatus) { case self::STATUS_ACTIVE: return '' . $statuses[$aStatus] . ''; case self::STATUS_INACTIVE: return '' . $statuses[$aStatus] . ''; default: return '' . $statuses[$aStatus] . ''; } } else { return $statuses[$aStatus]; } } public static function getStatuses() { return [ self::STATUS_BANNED => 'banned', self::STATUS_DELETED => 'deleted', self::STATUS_INACTIVE => 'inactive', self::STATUS_ACTIVE => 'active', ]; } } == Rules == Create basic rules: ''common/rbac/AuthorRule.php'': createdBy == $user : false; } } ''common/rbac/UserRoleRule.php'': user->identity->role)) { $role = \Yii::$app->user->identity->role; } else { return false; } if ($item->name === 'admin') { return $role == User::ROLE_ADMIN; } elseif ($item->name === 'editor') { // editor is a child of admin return $role == User::ROLE_ADMIN || $role == User::ROLE_EDITOR; } elseif ($item->name === 'author') { // author is a child of editor and admin return $role == User::ROLE_ADMIN || $role == User::ROLE_EDITOR || $role == User::ROLE_AUTHOR; } elseif ($item->name === 'poweruser') { // poweruser is a child of author, editor and admin return $role == User::ROLE_ADMIN || $role == User::ROLE_EDITOR || $role == User::ROLE_AUTHOR || $role == User::ROLE_POWERUSER; } elseif ($item->name === 'registered') { // registered is a child of author, editor, and admin. // if we have no role defined, this is also the default role. return $role == User::ROLE_ADMIN || $role == User::ROLE_EDITOR || $role == User::ROLE_AUTHOR || $role == User::ROLE_REGISTERED || $role == NULL; } else { return false; } } } == Init Script == Create console script ''console/controllers/RbacController.php'' to generate permissions and roles, then add them to users: authManager; $auth->removeAll(); // remove previous rbac data files under common/rbac/data //----------------------------------- // Rules //----------------------------------- // Add rules $ruleUserRole = new \common\rbac\UserRoleRule(); $auth->add($ruleUserRole); $ruleAuthor = new \common\rbac\AuthorRule(); $auth->add($ruleAuthor); //----------------------------------- // Permissions //----------------------------------- // Permission to create users $permCreateUsers = $auth->createPermission('createUsers'); $permCreateUsers->description = 'Create Users'; $auth->add($permCreateUsers); // Permission to edit user profile $permUpdateUserProfile = $auth->createPermission('updateUserProfile'); $permUpdateUserProfile->description = 'Update User Profile'; $auth->add($permUpdateUserProfile); // add "createContent" permission $permCreateContent = $auth->createPermission('createContent'); $permCreateContent->description = 'Create Content'; $auth->add($permCreateContent); // add "updateContent" permission $permUpdateContent = $auth->createPermission('updateContent'); $permUpdateContent->description = 'Update Content'; $auth->add($permUpdateContent); //----------------------------------- // Roles //----------------------------------- // add "registered" role with only basic permissions $roleRegistered = $auth->createRole('registered'); $roleRegistered->ruleName = $ruleUserRole->name; $auth->add($roleRegistered); // add permissions as children of 'registered' ... //none in this example // add "author" role, and give this role the "createContent" permission $roleAuthor = $auth->createRole('author'); $roleAuthor->ruleName = $ruleUserRole->name; $auth->add($roleAuthor); $auth->addChild($roleAuthor, $roleRegistered); // 'registered' is a child of 'author' // add permissions as children of 'author' $auth->addChild($roleAuthor, $permCreateContent); // editor role $roleEditor = $auth->createRole('editor'); $roleEditor->ruleName = $ruleUserRole->name; $auth->add($roleEditor); $auth->addChild($roleEditor, $roleAuthor); // 'author' is a child of 'editor' // add permissions as children of 'editor' $auth->addChild($roleEditor, $permUpdateUserProfile); // 'editor' can edit profiles $auth->addChild($roleEditor, $permUpdateContent); // 'editor' role can update content // add "admin" role and give this role the "updateContent" permission // as well as the permissions of the "author" role $roleAdmin = $auth->createRole('admin'); $roleAdmin->ruleName = $ruleUserRole->name; $auth->add($roleAdmin); $auth->addChild($roleAdmin, $roleEditor); // 'editor' is child of 'admin', for consequence 'author' and 'registered' is also child of 'admin' // add permissions as children of 'admin' $auth->addChild($roleAdmin, $permCreateUsers); // admin role can create users and also edit users because is parent of editor $auth->addChild($roleAdmin, $permUpdateContent); // admin role can update content //----------------------------------- // Permissions with dependencies in Roles/Rules //----------------------------------- // add the "updateOwnContent" permission and associate the rule with it. $permUpdateOwnContent = $auth->createPermission('updateOwnContent'); $permUpdateOwnContent->description = 'Update own content'; $permUpdateOwnContent->ruleName = $ruleAuthor->name; // add permissions $auth->add($permUpdateOwnContent); $auth->addChild($permUpdateOwnContent, $permUpdateContent); // "updateOwnContent" will be used from "updateContent" $auth->addChild($roleAuthor, $permUpdateOwnContent); // allow "author" to update their own contents //----------------------------------- // Roles assignment to users //----------------------------------- // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId() // usually implemented in your User model. $auth->assign($roleRegistered, 2 /* user_id */); $auth->assign($roleAdmin, 1 /* user_id */); } } == Default Role == Add support to set default user role when signing up new users. Modify ''frontend\models\SignupForm::signup()'' as follows: public function signup() { if ($this->validate()) { $user = new User(); ... $user->save(); // Set default role for new user. // This block is required when using authManager (see /common/config/main.php): $auth = Yii::$app->authManager; $authorRole = $auth->getRole('registered'); // set a default role, eg 'registered' $auth->assign($authorRole, $user->getId()); return $user; } return null; } == Initialize Database == If using ''yii\rbac\PhpManager'' (instead of ''DbManager''), create a data directory for RBAC settings files (items.php, assignments.php, rules.php): $ mkdir /common/rbac/data Execute console script: $ yii rbac/init If you need to create new permissions and/or roles: * Add permissions and roles to ''console/controllers/RbacController.php'', * Add new roles to ''common/rbac/UserRoleRule.php'' and to ''defaultRoles => [...]'' array in ''common/config/main.php''. * Execute the console script again. Eg: $ yii rbac/init == Getting Access == === Querying Permissions with user->can() === To use RBAC roles and permissions, use it like this: if(\Yii::$app->user->can('createUser')) { // call view with form to create users } else { // call view telling the users that cannot create users } // OR if (\Yii::$app->user->can('updateContent', ['content' => $content])) { // update content } === Querying Permissions with authManager->getRolesByUser() === use app\models\User; // Get user roles (requires authManager to be configured) if (in_array(User::ROLE_ADMIN, Yii::$app->authManager->getRolesByUser(Yii::$app->user->getId()))) { // Do something } === Applying Access Control Rules === For system wide access control, setup access control rules in the required controller. Eg: For ''CustomersController'', we need the following: public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'rules' => [ [ 'actions' => ['add'], 'roles' => ['manager'], 'allow' => true ], [ 'actions' => ['index', 'query'], 'roles' => ['user'], 'allow' => true ], ], ], ... ]; } == References == See also: * [[http://www.yiiframework.com/doc-2.0/guide-security-authorization.html|Yii 2 Guide: Security Authorization]] * [[http://www.fabioferreira.pt/rbac-with-yii2-user-quick-tutorial/|RBAC with Yii2-User - Quick Tutorial]] * [[http://www.yiiframework.com/forum/index.php/topic/60439-yii2-rbac-permissions-in-controller-behaviors/#entry269913|Forum: Yii 2 RBAC Permissions in Controller Behaviors]] * Sample RBAC implementations: * [[https://github.com/zelenin/yii2-rbac-module]] * [[https://github.com/vova07/yii2-rbac-module]] * [[https://github.com/trntv/yii2-starter-kit]]