I would like to provide you a quick tip on how to implement user level access to your Yii applications.
Please note that this article is a simple example and good security should be taken into account when we play with authentication systems.
a. Include a field on your user’s table named, yep you guessed, level
b. Create an object ‘LevelLookUp’ that will tell us who is who on this system
class LevelLookUp{ const MEMBER = 0; const ADMIN = 2; // For CGridView, CListView Purposes public static function getLabel( $level ){ if($level == self::MEMBER) return 'Member'; if($level == self::ADMIN) return 'Administrator'; return false; } // for dropdown lists purposes public static function getLevelList(){ return array( self::MEMBER=>'Member', self::ADMIN=>'Administrator'); } }
c. Now, lets modify UserIdentity, located on your protected/components (normally by default), so we can store the user Model id on successful authentication, as CWebUser’s id property is set to the user Model’s username by default.
class UserIdentity extends CUserIdentity { private $_id; /** * Authenticates a user. * @return boolean whether authentication succeeds. */ public function authenticate() { $username = strtolower($this->username); // from database... change to suite your authentication criteria // -- Nope, I wont include mine -- $user = User::model()->find('LOWER(username)=?', array($username)); if($user===null) $this->errorCode=self::ERROR_USERNAME_INVALID; else if(!$user->validatePassword($this->password)) $this->errorCode = self::ERROR_PASSWORD_INVALID; else{ // successful login $this->_id = $user->id; $this->username = $user->username; $this->errorCode = self::ERROR_NONE; } return $this->errorCode == self::ERROR_NONE; } public function getId() { return $this->_id; } }
d. Now we need to create our own extended CWebUser and we are going to call it EWebUser for the sake of this example, and save it on protected/components to be loaded automatically by our default’s configuration file.
class EWebUser extends CWebUser{ protected $_model; function isAdmin(){ $user = $this->loadUser(); if ($user) return $user->level==LevelLookUp::ADMIN; return false; } // Load user model. protected function loadUser() { if ( $this->_model === null ) { $this->_model = User::model()->findByPk( $this->id ); } return $this->_model; } }
e. Finally, we modify main.php config file (this file is in protected/config folder) to tell Yii that we want to use our extended version of CWebUser.
// go to the 'user' section // application components 'components'=>array( 'user'=>array( // There you go, use our 'extended' version 'class'=>'application.components.EWebUser', // enable cookie-based authentication 'allowAutoLogin'=>true, ),
Now that we know, who logged, we could easily find out if it is just a member or an administrator and render the elements by checking the level as simple as this:
// for normal content if(Yii::app()->user->isAdmin()) echo 'Is administrator'; // for CMenus $this->widget('zii.widgets.CMenu',array( array('label'=>'Categories', 'url'=>array('/category/index'), 'visible'=>(Yii::app()->user->isAdmin()), //... More stuff //... // for data chuncks <?php if(Yii::app()->user->isAdmin():?> <b>My HTML</b> <?php endif;?> // for access rules return array( array('allow', 'actions'=>array('create','delete','update'), 'expression'=>'$user->isAdmin()' ), // ...
You can create more methods, like for example, isMember(), or whatever best suits you, in order to display the appropriate view or specific data according to the user level.
Total 9 comments
Please take a look.why this problem occur with module based login. http://www.yiiframework.com/forum/index.php/topic/37991-module-based-login-and-user-level-acces-system
I am trying to implement this nice little access system as well but I am getting a Property "UserIdentity.id" is read only error. Any suggestions?
Thank you for these explanations. It works perfectly, i just don't understand the way to use LevelLookUp in gridview and listview of user's grids. Could you explain more?
simple n effective.. short n fast way to get a access system up
Really easy !
Thank you again derelict... Code modified...
You have override CUserIdentity class and now it's getter getId() returns user's ID, not username. That's why in EWebUser class getter getId() will return user's ID too.
Thanks for pointing me the little bug! I forgot to remove that.
About using setState and getState I used to keep the model's id instead of the username as it internally does, and didn't want to modify CWebUser defaults, that's why I used another variable name (__uid)
Thanks again!
Thank you for your article. But I think you have error in this line of EWebUser class:
And why do you use setState/getState? I think that CWebUser stores id itself using this methods.
Leave a comment
Please login to leave your comment.