Simple Authentication with the Yii Framework

January 4, 2010 — 68 Comments
The Yii Book If you like my writing on the Yii framework, you'll love "The Yii Book"!

I wanted to write up a strong post on Access Control Lists in Yii, for controlling who can do what in an application. I still will, of course, but since authorization depends upon authentication, I thought it necessary to discuss Yii’s authentication system first. And, as happens with me, in writing about that, and how you would customize the authentication process, I had to break the subject down into two posts. So here’s the first of an informal three-part series on authentication and authorization in Yii. In this post, I discuss how the parts of Yii’s authentication system work together; much of what I say in this first post is also available in the Yii documentation, just not presented in this way. I also show a couple of quick ways to modify its behavior to suit your situation.

Most sites use some form of authentication. Maybe users have to login to post questions, to read content, or to administer the site. Whatever the case, a verification of the person is required before they can do whatever. As this is standard behavior, the default application created by the Yii framework has built-in authentication. When you generate a new site using Yii’s command-line tools, three files for managing authentication are created:

  • protected/components/UserIdentity.php
  • protected/models/LoginForm.php
  • protected/views/site/login.php

And there’s also some code added to protected/controllers/SiteController.php that comes into play. The Controller file, gets the action going, of course. The View file is the login form itself. The LoginForm Model file defines the rules and behavior and the UserIdentity file defines a Model that performs the actual authentication.

By default, if you do nothing at all, users will be allowed to log into the site using the username/password combinations of demo/demo or admin/admin. These values are set in the UserIdentity.php script. If all you need to do is allow only a single authenticated user, then you can open UserIdentity.php and change this code:

$users=array(
    // username => password
    'demo'=>'demo',
    'admin'=>'admin',
);

to

$users=array(
    'whateverName'=>'whateverPassword'
);

At that point, you’re done. However, you most likely will perform authentication against a database table, so let’s see how you’d edit these files to make that happen. To start, let’s assume that the table name is Users, that you’ve already generated a Model for it, and that authentication requires an username and a password. As you’ll see, you’ll still only need to edit the UserIdentity.php file to make this possible, but in my next post I’ll walk through more elaborate customizations. Okay, with that in mind, let’s examine the authentication process…

The URL to login will likely be www.example.com/index.php/site/login, as Yii puts login/logout functionality in the Site Controller by default. So when the user clicks on a link to go to the login page, they’ll go through the Site Controller and call the actionLogin() method. That method is defined as:

public function actionLogin()
{
    $form=new LoginForm;
    // collect user input data
    if(isset($_POST['LoginForm']))
    {
        $form->attributes=$_POST['LoginForm'];
        // validate user input and redirect to previous page if valid
        if($form->validate()  && $form->login()) $this->redirect(Yii::app()->user->returnUrl);
    }
    // display the login form
    $this->render('login',array('form'=>$form));
}

First, a new object is created of type LoginForm. That class is defined in the LoginForm.php Model file. If the form has been submitted, the form data is collected and the data is validated. If the data passes the validation, the user will be redirected to whatever URL got them here in the first place. If the form has not been submitted, or if the form data does not pass the validation routine, then the login form is displayed, and it is passed the LoginForm object. The default login form looks like this (note the reference to demo/demo and admin/admin, already discussed):

Yii Login Form

Now, the call to the validate() method in the above code means that the form data has to pass the validation rules established in the LoginForm class. This is basic Model validation as defined by the rules() method of the Model (also see my post on basic Model edits):

public function rules()
{
    return array(
        // username and password are required
        array('username, password', 'required'),
        // password needs to be authenticated
        array('password', 'authenticate'),
    );
}

As you can see, those rules say that both the username and password are required and that the password has to pass the authenticate() method. This is not a built-in validation routine, but is defined in LoginForm. The LoginForm::authenticate() method starts off like so:

public function authenticate($attribute,$params)
{
    if(!$this->hasErrors())  // we only want to authenticate when no input errors
    {
        $identity=new UserIdentity($this->username,$this->password);
        $identity->authenticate();
        switch($identity->errorCode)

If there are no errors when this method is called (an error would be a lack of a username or password), a UserIdentity object is created, passing that object the submitted username and password. Then the UserIdentity object’s authenticate() method is called. This gets us to protected/components/UserIdentity.php, which defines the class and the method. If you’re having trouble following the process thus far, here it is pictorially:

Yii Auth Process

Note that any errors stops the process from continuing and just re-displays the login form, with the errors reported.

As I already wrote above, the UserIdentity authenticate() method as written compares the submitted values against predefined combinations and returns a message accordingly. If you want to test the submitted values against the database, you’ll need to add some code. Start by fetching the record for the given username:

class UserIdentity extends CUserIdentity
{
    public function authenticate()
    {
        $user = User::model()->findByAttributes(array('username'=>$this->username));

Now the $user object represents the User record with an username field equal to the submitted username. (The CUserIdentity class’s constructor takes the provided username and password and stores them in $this->username and $this->password, just to be clear.) You could, and might be inclined, to attempt to retrieve the record that matches both the username AND the password, but if you were to do that, you wouldn’t be able to provide more meaningful error messages: username doesn’t exist, username does exist but the password doesn’t match, and so forth.

Next the authenticate() method should check a series of possiblities and assigns constant values to the errorCode variable:

if ($user===null) { // No user found!
    $this->errorCode=self::ERROR_USERNAME_INVALID;
} else if ($user->pass !== SHA1($this->password) ) { // Invalid password!
    $this->errorCode=self::ERROR_PASSWORD_INVALID;

In the first conditional, if $user has no value, then no records were found, so the username was incorrect. In the second conditional, the stored password is compared against the SHA1() version of the submitted password. This assumes the record’s password was stored in a SHA1() encrypted format. If neither of these conditionals are true, then everything is okay:

} else { // Okay!
    $this->errorCode=self::ERROR_NONE;
}

Finally, the method returns a boolean value, indicating an error or not:

return !$this->errorCode;

The presence of an error code gets used in the authenticate() method of the LoginForm Model, in response to the authentication attempt (this is a continuation of the LoginForm::authenticate() code shown above):

$identity->authenticate();
switch($identity->errorCode)
{
    case UserIdentity::ERROR_NONE:
        $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
        Yii::app()->user->login($identity,$duration);
        break;
    case UserIdentity::ERROR_USERNAME_INVALID:
        $this->addError('username','Username is incorrect.');
        break;
    default: // UserIdentity::ERROR_PASSWORD_INVALID
        $this->addError('password','Password is incorrect.');
        break;
}

So if there was no error, the user is logged in. The duration—the period for which they’ll be logged in—is either 30 days or for just the session, depending upon whether they checked the rememberMe box or not (see the login form image). If either error is present, it’ll be added to the current object, the validation will fail, meaning that the conditional in the actionLogin() method of SiteController.php will be false, and the login form will be rendered again, this time with the error message. The whole process therefore becomes:

Yii Auth Process, Complete

That’s an outline of the basic process, using a User Model (based upon a database table), instead of hard-coded values. All of this information can also be found in the Yii documentation, just not written quite like this. To take this information further, and to make it more practical, my next post will show you how to modify all of the Yii-generated code in order to:

  • Store the user’s ID so it can be referenced as they peruse the site
  • Store the user’s “role”, like reader, editor, and writer, as well.
  • Authenticate the user with their email address and password, not their username.

That post will follow in just a couple of days. EDIT: Here it is! As always, thanks for your interest in what I have to say and let me know if you have any questions or comments. Thanks, Larry

If you enjoyed this post, then please consider following me using your favorite social media, the RSS feed, and/or by subscribing to my newsletter. Or go crazy, and buy one or more of my books . Thanks!

68 responses to Simple Authentication with the Yii Framework

  1. From security point of view, it is better to show an user error message of the form “the username and password combination is not correct” for both invalid username and invalid password. You may of course, log them separately.

    Another important aspect is to avoid storing the password in plain text. Each password should be hashed with a random salt value.

    • Thanks for your comments. Yes, it’s absolutely true that it’s more secure to show less detailed messages, but that’s also less convenient for your users, so you have to decide where to strike that balance. And, of course passwords ought to be stored in an encrypted format. The default Yii setup has these stored in an un-encrypted format in the text file.

  2. how to set session value after logging in? thanks

  3. how to use session on controller, how to create, or check, or modify for example…. for this reason I’m looking for a tutorial. i just can’t find any related specific document at yii website and its forum other than API and simple setting in main.php. appreciate

  4. Seriously bro, without your online tutorials the yii community is lacking good insightful and error free information on how to get use out of the framework…

    I have been working with Yii for a day now going though every tutorial on the internet and they all lead to a lot of outside research and filled with errors if they work at all…

    Your blog series is like a goldmine! Everything works perfect and has gotten me up and running in no time from straight php code to now using a framework.. There is not even books on this framework yet but its an awesome framework…

    GOOD JOB!!! keep posting more about Yii

    • Thank you. Very nice to say. I do like Yii, too, and there will certainly be more posts to come. I believe there is a Yii book in the works, by the way, from Packt Publishing.

  5. Awesome!!! Cant wait to get the book, i just checked out the Bio on it….

    • Just to be clear, in case it wasn’t, the book is not being written by me. In fact, I don’t know anything about it. But it’s good to see a Yii book coming out.

  6. Thank you for your straightforward tutorials. They’re better than the original author’s.
    BTW, I think you forgot to add && $form->login(…) after $form->validate() in function actionLogin(). CMIIW.

  7. Hello Larry,

    your tutorial is impressive! i’ve been looking for good php mvc framework, and I am too confused where what to pick, and honestly Yii is good.

    I am now following you tutorial and i am gaining, thanks!

    now I have a simple question you said that the below code is found in useridentify.php

    $users=array(
    // username => password
    ‘demo’=>’demo’,
    ‘admin’=>’admin’,
    );

    to

    $users=array(
    ‘whateverName’=>’whateverPassword’
    );

    but i couldn’t find this part, could you help please?

    big thanks

    • Thanks for the nice words. What, exactly, couldn’t you find? The assignment to the $users variable in userIdentify.php?

      • Hello Larry,

        you could see this after 4th paragraph of this tutorial…[SNIP]
        but could not find this in useridentity.php (sorry i posted useridentify.php)

        thanks for your help,

        • Right. I’m fairly well aware of what I wrote just above. I’m asking what specific code could you not find in UserIdentity.php.

          • Oh im so sorry,

            this is the piece of code missing.

            $users=array(
            // username => password
            ‘demo’=>’demo’,
            ‘admin’=>’admin’,
            );

            which you said found in UserIdentity.php, but i could not find it.

            thanks

            thanks

          • That surprises me. I didn’t test this in Yii 1.1.6 yet, but even in Yii 1.1.5, that code was corrected. What does the authenticate() method of your protected/components/UserIdentity.php script look like?

  8. As an FYI, I have a 1.1.5 and 1.1.6 installed, and the code remains the same. By default, that code is on line 20 of the ‘components\UserIdentity.php’ file in the protected folder (whereever that may be within your site setup).

  9. The tutorial is very impressive. i had some problem related to login but when i read this i solved my problem so i want to say thanks for this tutorial. Once again thank you very much.

  10. thanks for the great tutorials Larry. Very much appreciated.

    When I copied the code:
    if ($user===null) { // No user found! $this->errorCode=self::ERROR_USERNAME_INVALID; } else if ($user->pass !== SHA1($this->password) ) { // Invalid password! $this->errorCode=self::ERROR_PASSWORD_INVALID;

    I got an error with $user->pass. I changed this to $user->password and this fixed it. This may help others.

    Thanks again.

  11. Hello Larry !

    Nice and useful post.
    I am new to Yii and I want to ask you this:
    How can I proceed to make the authentication the first thing to happen when a web application starts?

    I see in the examples how the user is asked to login if there is not an active user yet in the application, but I would like the user to login at first, before he/she starts exploring the application.
    Do you have an example of how to do this?

    Regards.

    • Thanks for the nice words. There is an example on one of these blog postings for doing exactly that, perhaps in the sequel to this one? I don’t remember offhand, but if you search or use the Yii tag, you should be able to find it.

  12. My log in Session is not working when i try connecting it to a database. I followed the same procedures said above. Can someone help me

    • Not with the (lack of) information provided. I’d recommend using the Yii support forums and providing many more details when you do so.

  13. Hi! Mr. Larry im just new in programming
    after following all the steps above i got this error message after logging in

    Fatal error: Call to a member function authenticate() on a non-object in C:\xampp\htdocs\juhn\protected\models\LoginForm.php on line 51

    LoginForm
    public function authenticate($attribute,$params)
    {
    if(!$this->hasErrors())
    {
    $this->_identity->authenticate(); -> this is line 51
    switch($this->_identity->errorCode)
    {
    case UserIdentity::ERROR_NONE:
    $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
    Yii::app()->user->login($this->_identity,$duration);
    break;
    case UserIdentity::ERROR_USERNAME_INVALID:
    $this->addError(‘username’,’Username is incorrect.’);
    break;
    default: // UserIdentity::ERROR_PASSWORD_INVALID
    $this->addError(‘password’,’Password is incorrect.’);
    break;
    }
    }
    }

    and im using yii 1.1.8

    or can you give me steps how to create an admin user and a normal user from my table User
    thanks

  14. thanks you for this informative tutorial, larry!

  15. Hi Larry,

    I was following along your tutorial on authentication but I could not make the login work
    with the below code. (using UserIdentity code) On DB, I have the same db schema as the
    the blog tutorial on yii site (has User table with username column) for yii 1.1.8.

    I get a blank screen upon submitting login.

    When I step the code using the xdebug debugger, the $user object does not seemed to be constructed correctly. I can not step past the line:
    if($user===null)

    When I inspect $user object, I only see the classname with no other attributes.
    Wondering if you can give me any advice.

    class UserIdentity extends CUserIdentity
    {
    private $_id;

    public function authenticate()
    {
    $username=strtolower($this->username);
    $user = User::model()->findByAttributes(array(‘username’=>$this->username));

    if($user===null)
    $this->errorCode=self::ERROR_USERNAME_INVALID;
    else
    if(!$user->validatePassword($this->password))
    $this->errorCode=self::ERROR_PASSWORD_INVALID;
    else
    {
    $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;
    }
    }

  16. Hi, Larry!

    >> $form->validate() && $form->login()
    LoginForm::authenticate() and LoginForm::login() both validate user password. LoginForm::login() can be removed. Isn’t it?

    Thanks for post!

    • It’s been a while since I looked at this, but I thought validate() validated the data against the Model rules (as it does in any Model) and login() actually validated the data against the stored values in the database.

  17. Hi Mr. Larry… Thanks so much for the clear explanation… You should write the Yii documentation ;-)… I just don’t get the line “return !$this->errorCode;”… Why the “!” is needed here? We don’t wanna jus return the errorCode? Tanks a lot for your help…

    Best regards,
    Cleverson

    • Thanks for the nice words. Much appreciated. That line in question doesn’t return the error code, it returns a Boolean indicating whether there is an error code or not. So if $this->errorCode has a value, then the opposite–false–is returned, indicating that things didn’t work well. If $this->errorCode does not have a value, then true is returned, indicating that things worked fine.

  18. Hi,
    This article is awesome. It helped a lot as a beginner in YII framework.
    Thanks a lot.

  19. thanks larry, u r a life saver

  20. I need a login for administrator,employee with the same login form You above mentioned.that is username and password from database.how it is done .Please give me any information?

    Regards
    Shymet M

  21. Hello Larry,

    A big THANK YOU to you! you certainly made Yii what it is ‘Yes it is’ – I struggled with all the other material available on-line (esp. the Yii official documentation!) and sometimes had no clue what the author(s) were talking about – but your blog has made it so very clear – that I have recommended Yii to others and your blog with it. Thanks heaps :)

  22. Hello,
    First, thank for your articles. Great help.

    I’m trying to implement this.
    I think you have a type error

    } else if ($user->pass !== SHA1($this->password) ) { // Invalid password!
    should be
    } else if ($user->password !== SHA1($this->password) ) { // Invalid password! // see password instead of pass

    I’ll keep on trying to implement.
    best regards
    Olivier.

    PS, as a remark, I would add that I succeed in finding some of your articles only via google.
    this article we’re discussing, for instance, http://www.larryullman.com/2010/01/04/simple-authentication-with-the-yii-framework/
    does not appear in your “Yii series” and when searched on your search box on your site. (I am sorry if I make a mistake).

    Your input is so valuable, it would deserve to be well listed on your website, with all your Yii tutarials well listed and easily available.
    Again sorry if I missed the point, and this is purely to help (me and the others) and not to criticize.

  23. hi larry

    whem i call $model=new LoginForm;

    a session is already being set & ican view the session file in the tmp folder, any idea y this is happening.

    I seriously want o remove this session file.

  24. I must, as many have done before me, express how well-written and helpfull your tutorials are. Great work.

    One small change from the version this tutorial was made for:
    The $identity var is no longer used, instead they use $this->_identity, and therefore a small change in code is needed.

    Here is my suggestion:

    public function authenticate($attribute,$params)
    {
    if(!$this->hasErrors())
    {
    $this->_identity=new UserIdentity($this->username,$this->password);

    $this->_identity->authenticate();
    switch($this->_identity->errorCode)
    {
    case UserIdentity::ERROR_NONE:
    $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
    Yii::app()->user->login($this->_identity,$duration);
    break;
    case UserIdentity::ERROR_USERNAME_INVALID:
    $this->addError(‘username’,’Username is incorrect.’);
    break;
    default: // UserIdentity::ERROR_PASSWORD_INVALID
    $this->addError(‘password’,’Password is incorrect.’);
    break;
    }
    }
    }

  25. Larry – thanks for the tutorial, however, I have been trying for days to get this to work. Maybe I’m just stupid. I just tried Jorgen’s update, but that did not help – Thank you Jorgen for posting. I need some major help. I’m getting a CException error displayed when attempting the login. What support forum should I post in.

  26. sir please share model and controller files . i followed this process . but i was failed . kindly please share those files. its very need for me

  27. daniel de suze May 4, 2013 at 8:23 pm

    hi i’m new at yii and i just wanted to know how to create a sign up form that would enter the user name and password to a database. and when they are logging back in would access the database to see whether the identity is there and deliver the necessary steps after.

  28. hi getting this error when i execute the link
    http://localhost/yii/test/index.php?r=site/login
    plz do the needful

  29. error getting is
    Fatal error: Call to a member function isAttributeRequired() on a non-object in C:\xampp\htdocs\yii\framework\web\helpers\CHtml.php on line 1237

  30. Hi Larry. Will You please tell me that how to create an admin section in yii framework???

  31. Hi. I am newbie. I exactly want sso in yii. single sign on between yii and non yii app. i dont know what to do. please help me detail.

  32. Hi Larry. How to set a login form as the home page.

  33. Hello Larry,
    Congrats you have done a great job by writing yii book. It is helping new coders like me.
    I have gone through your book and successfully implemented DB Auth.
    I have one question that is as follows:
    I want to introduce some more secure mechanism in it.
    1. A salt field in DB for each user. This new salt field will be created on new user creation.
    $random_salt = hash(‘sha512′, uniqid(mt_rand(1, mt_getrandmax()), true));
    2. Password will be hashed using SHA512 Algorithm.
    $password = hash(‘sha512′, $password.$random_salt);
    =>Now how can I access salt field in validatePassword() function ?
    => If I want to generate a new salt on each successful login how can i insert new salt value via afterValidate() routine?

  34. Hi,

    Thanks for this article,

    I am new to yii and it helps me a lot.

  35. Hi,
    If anyone is interested in using modules for user management and social authentication, here’s a tutorial you might find useful: http://www.ponomaryov.org/yii-tutorials/beginners-tutorial-integrating-user-management-and-oauth-into-a-yii-project/
    Cheers!

Comments are great, but I'd strongly prefer any requests for assistance get made in the support forums. Thanks!