Yii 1.1: Implementing a User Level Access System

40 followers

Introduction

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.

Step 1. Setting up

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 (create LevelLookUp.php inside protected/component/)

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 suit 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,
        ),

Step 2: Putting everything together

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 12 comments

#14303 report it
MissChile at 2013/08/03 01:47pm
Step 2, Where?

Hi! Thanks for this. I'm new with Yii and I would like to try this but I don't know which file I have to modify in step 2. Do I have to add that code in the main.php file in layouts?

Thanks in advance!

#13762 report it
HSarman at 2013/06/23 06:48pm
Simple&Clear Thx

This tutorial helped me alot thx.

To Kashif Nadeem cerate a php file LevelLookUp.php inside protected/component/

#13685 report it
Kashif Nadeem at 2013/06/17 06:05am
b. Create an object ‘LevelLookUp’ that will tell us who is who on this system

Where i will use create this object b. Create an object ‘LevelLookUp’ that will tell us who is who on this system

Kashif

#10856 report it
hemc at 2012/11/28 01:08am
problem when implement with module based login to module.

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

#9109 report it
otter at 2012/07/20 12:52pm
Read only problem

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?

#7279 report it
ragua at 2012/03/09 06:11am
Thank you

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?

#6048 report it
Malcolm Y. at 2011/12/08 02:34am
thanks!

simple n effective.. short n fast way to get a access system up

#3961 report it
RusAlex at 2011/05/24 02:04am
nice article

Really easy !

#3837 report it
Antonio Ramirez at 2011/05/13 01:46am
@derelict

Thank you again derelict... Code modified...

#3829 report it
derelict at 2011/05/12 06:57am
User's ID

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.

#3828 report it
Antonio Ramirez at 2011/05/12 06:37am
@derelic

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!

#3824 report it
derelict at 2011/05/11 05:53pm
Thank you

Thank you for your article. But I think you have error in this line of EWebUser class:

if ( $id !== null )

And why do you use setState/getState? I think that CWebUser stores id itself using this methods.

Leave a comment

Please to leave your comment.

Write new article