UPDATE: Starting with version 2.0.2, Yii2 Advanced Template does not contain “role” column in the User table by default. Before proceeding to the tutorial below, do the following:
- Create a column called role in the user table.
- Update the User model by adding the role attribute and updating the User class docblock accordingly.
Yii 2.0 has a built in Access Control that supports 2 roles out of the box to check whether the user is a guest or if the user is logged in. Sometimes there is a need to simply extend the Access Control Layer with few more roles to distinguish the logged in users i.e. admin, moderator, without the full blown RBAC graph with permissions, roles and role assignments that Yii provides.
In this post, I will show how to implement simple Role Based authorization by simply extending the AccessRule class that defines the default rules and overriding the matchRule() function call, which will provide the additional rule matching logic.
I will be using the advanced template, but you can adapt the code to basic template without much difficulty. The concept remains the same in both.
Let’s start by defining our roles. I will be creating 2 new roles, namely Admin and Moderator, in addition to the existing User role. These roles will allow us to distinguish the roles of the logged in users, and also allow us to restrict access to different parts of the application depending on the role assigned to the user.
Let’s get started with some code.
- Create a AccessRule class that extends the \yii\filters\AccessRule class. I have chosen to do so inside the common\components namespace. You may need to create the components folder inside common folder. Populate common\components\AccessRule.php with the following code:
<?php namespace common\components; class AccessRule extends \yii\filters\AccessRule { /** * @inheritdoc */ protected function matchRole($user) { if (empty($this->roles)) { return true; } foreach ($this->roles as $role) { if ($role === '?') { if ($user->getIsGuest()) { return true; } } elseif ($role === '@') { if (!$user->getIsGuest()) { return true; } // Check if the user is logged in, and the roles match } elseif (!$user->getIsGuest() && $role === $user->identity->role) { return true; } } return false; } }
Here we are overriding the matchRole() function. Much of the matchRole() code is copied from the \yii\filters\AccessRule class except we have now changed the last elseif-statement to match the role supplied inside the controller with the role defined in the database and the User model.
- Inside the common/models/User.php, we will define our new roles. There is already a const ROLE_USER = 10; in the User model. We will add our new roles right below it so that our role constants look like this:
const ROLE_USER = 10; const ROLE_MODERATOR = 20; const ROLE_ADMIN = 30;
- Now it’s time to use our new roles inside the controller. To use the new roles, we will use the new AccessRule component and make slight changes to the access behavior. Add the following use statements on top of your controller:
use common\components\AccessRule; use common\models\User;
Edit the access behavior as follows:
'access' => [ 'class' => AccessControl::className(), // We will override the default rule config with the new AccessRule class 'ruleConfig' => [ 'class' => AccessRule::className(), ], 'only' => ['create', 'update', 'delete'], 'rules' => [ [ 'actions' => ['create'], 'allow' => true, // Allow users, moderators and admins to create 'roles' => [ User::ROLE_USER, User::ROLE_MODERATOR, User::ROLE_ADMIN ], ], [ 'actions' => ['update'], 'allow' => true, // Allow moderators and admins to update 'roles' => [ User::ROLE_MODERATOR, User::ROLE_ADMIN ], ], [ 'actions' => ['delete'], 'allow' => true, // Allow admins to delete 'roles' => [ User::ROLE_ADMIN ], ], ], ],
In the above example, we are first overriding the ruleConfig of the access behavior with our new AccessRule class. Then there are 3 actions create, update and delete which are controlled by our new AccessRule class and the following rules are applied.
- create action is available to User, Moderator and Admin roles.
- update actions is available to Moderator and Admin roles.
- delete action is only available to the Admin role.
There you have it. Clean and simple role based authorization for applications that require more than simple logged-in check, but don’t require full blown Role Based Access Control provided by Yii 2.0.
Further Reading
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
http://www.yiiframework.com/doc-2.0/yii-filters-accessrule.html
http://www.yiiframework.com/doc-2.0/yii-filters-accesscontrol.html
Bonus Tip
Go through the Yii 2.0 source code. There are many times where you will think “Yii does x very nicely, I wish it did y too in the same manner”. The way Yii is structured, it is very easy to extend the functionality on top of the core Yii library without changing the core files. The core Yii code is very well commented and organized and it is a good source of learning PHP itself.
Any intro to frameworks would be good, by the way i liked the post, but i’ve never used frameworks.
Hi, Thank you. It works like a charm.
How do I set the role of logged in User in $user->identity->role ???
Hi Ankur,
Starting with v2.0.2, the advanced template no longer has role attribute included by default. To get the above tutorial working, do these 2 extra steps:
1. Create a column called “role” in the user table.
2. Update the User model by adding the role attribute and updating the docblock accordingly.
From then on, make sure you assign a role to all users upon creation.
I will update the post with proper code at a later time.
Good luck!
Thank you so much.This article helps me a lot.
Great article and very useful for most people who need some level control and not the full blow RBAC. This should be default yii capability but for some reason they give you an all or nothing option instead.
Great job.
The only thing I would recommend is giving more info on adding “role” to the User model as it was a bit tricky to figure out when the model does not contain it at all.
Thank you
How do I check if a user has permission to an action? In order to display the proper menu.
Thank you!
Hi Max,
Look at the point #3 regarding ‘access’ behavior in the controller. There are 2 main steps:
1. Overriding the ruleConfig class with the one we created;
2. Setting up the rules array to allow/deny access to certain roles.
What is the data type of role in User table? Is it varchar or int? Thanks.
The data type can be anything you would like it to be. I like to keep it as int, and then in the model define the roles as constants i.e. ROLE_ADMIN = 1, ROLE_USER = 2 and so on.
It says “Class ‘frontend\controllers\AccessControl’ not found”. How do it fix this? Thanks
Hi,
Try using
'class' => \yii\filters\AccessControl::className(),
in the access behavior definition.My IDE has code completion and detects the AccessControl in the correct namespace.
Hope this helps.
hii i m using the basic template of yii 2
its says Class ‘app\components\AccessRule’ not found
what should i do ?
thank you in advance
Is it possible to integrate Simple Role Based Authorization to Humhub with a module like “Privacy” or “AccessControl”?
Hi,
I am not an expert on HumHub and currently cannot go through the source. Maybe open an issue on HumHub’s github repo and request the integration?
I got this error :-
Forbidden (#403)
You are not allowed to perform this action.
Can you help me solve it? im using yii2 advanced template, and followed steps above.
I have the same issue as the user above. I want to allow/deny the whole controller (not just some actions) to anyone who’s not the admin, so I have this behavior:
‘access’ => [
‘class’ => AccessControl::className(),
‘ruleConfig’ => [‘class’ => AccessRule::className()],
‘only’ => [‘index’,’create’,’update’,’delete’,’view’],
‘rules’ => [
[
‘actions’ => [‘index’,’create’,’update’,’delete’,’view’],
‘allow’ => true,
‘roles’ => [User::ROLE_ADMIN],
],
],
I also tried taking out actions and only but the result is the same.
Yeah, this article should be linked first from these pages:
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
http://www.yiiframework.com/doc-2.0/yii-rbac-phpmanager.html
Wasn’t easy to find, but it’s perfect.
Hey Thank you
showing Access denied any demo github please
I use this tutorial at the basic project but it does not work.I make the role field and insert the code as explained.At user model etc.
The user can not see the action even I have the write “10” at role field
Really very great tutorial
Can we put in hte config main.php
like
‘components’ => [
………………
“ruleConfig” => [“class” => “frontend\components\extra\AccessRule”],
…………………..
]
so i dont have to write “ruleConfig” => [“class” => “frontend\components\extra\AccessRule”], on every controller, in case the class changed again
please reply
Hello,
Is it possible to allow user to update his/her own Record using above rules? If possible than how?
I’d like to know this as well…
Thanks for the idea! It worked with minor changes.
I had to change $user->getIsGuest to $user->IsGuest
Please add how to put the component into the config/web.php.
Otherwise, nice tutorial, thanks!
Hello,
Nice article
There is no User::ROLE_USER, in common\models\User. The only const we have is const STATUS_ACTIVE = 10;
Please correct you code so that i know what to do.
Thanks
There is no
const ROLE_USER = 10;
in the User.php in common\models. There are only
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
what am I doing wrong?
Hi.
Just add those properties to your model.
Hi sir! I followed your tutorial and I got an error:
Unknown Property – yii\base\UnknownPropertyException
Setting unknown property: common\components\AccessRule::ruleConfig
How can I solve this?
Hi.
Nice article. Simple enough but useful to start.
Thanks.
I would also like to know how to get this setup in the config/web.php file so it applies to the whole site rather than having to put this in each individual controller.