<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:series="http://unfoldingneurons.com/"
><channel><title>Larry Ullman &#187; auth</title> <atom:link href="http://www.larryullman.com/tag/auth/feed/" rel="self" type="application/rss+xml" /><link>http://www.larryullman.com</link> <description>Translating Geek Into English</description> <lastBuildDate>Sun, 05 Feb 2012 17:48:42 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <item><title>Forcing Login for All Pages in Yii</title><link>http://www.larryullman.com/2010/07/20/forcing-login-for-all-pages-in-yii/</link> <comments>http://www.larryullman.com/2010/07/20/forcing-login-for-all-pages-in-yii/#comments</comments> <pubDate>Tue, 20 Jul 2010 01:45:17 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[auth]]></category> <category><![CDATA[framework]]></category> <category><![CDATA[mvc]]></category> <category><![CDATA[yii]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=1195</guid> <description><![CDATA[Some time back, I had written a couple of blog posts on authentication and authorization in Yii. As a comment to one of those posts, someone shared some code (also posted in the Yii forums) that requires a login to access any page. The interesting thing about this code is that it&#8217;s placed in the [...]]]></description> <content:encoded><![CDATA[<p>Some time back, I had written a couple of blog posts on <a
href="http://www.larryullman.com/2010/01/07/custom-authentication-using-the-yii-framework/">authentication</a> and <a
href="http://www.larryullman.com/2010/01/14/yii-framework-access-control-lists/">authorization</a> in <a
href="http://www.yiiframework.com/">Yii</a>. As a comment to one of those posts, someone shared some code (also posted in the Yii forums) that requires a login to access any page. The interesting thing about this code is that it&#8217;s placed in the primary application configuration file, not within individual Controllers. The benefit to this approach is that a little bit of code can add authorization to your entire site, no matter how many Controllers you have. I&#8217;ll explain how to use this approach in this post, although keep in mind that it&#8217;s really best for situations where users must be logged in to access almost all of the site&#8217;s content.<span
id="more-1195"></span>The very first step uses the <span
style="text-decoration: underline;">protected/config/main.php</span> configuration file. That configuration file returns an array of values. Within that primary array (i.e., not within any of the subsections), you&#8217;ll want to add:</p><pre>'behaviors' =&gt; array(
    'onBeginRequest' =&gt; array(
        'class' =&gt; 'application.components.RequireLogin'
    )
),
</pre><p>By placing this within the primary array, it applies to the application as a whole, as opposed to a specific component or module. This code associates one class with the <strong>onBeginRequest</strong> behavior. This is to say that every time a request is made, an instance of the <strong>RequireLogin</strong> class should be created.</p><p>Next, create a file called <span
style="text-decoration: underline;">RequireLogin.php</span> and store it in the <span
style="text-decoration: underline;">protected/components</span> directory. That file needs to define the <strong>RequireLogin</strong> class, which should be an extension of the Yii <strong>CBehavior</strong> class, which defines how application behaviors are used:</p><pre>&lt;?php
class RequireLogin extends CBehavior
{
}
?&gt;</pre><p>Within that class, only two methods need to be defined. The first is <strong>attach()</strong>, which will associate an event handler with the application:</p><pre>public function attach($owner)
{
    $owner-&gt;attachEventHandler('onBeginRequest', array($this, 'handleBeginRequest'));
}</pre><p>This method will receive the application as an argument (this code was found in the Yii forums, too). The <strong>attachEventHandler()</strong> function attaches to the application an event handler, saying that when the <strong>onBeginRequest</strong> event occurs, this class&#8217;s <strong>handleBeginRequest()</strong> method should be called.</p><p>The <strong>handleBeginRequest()</strong> method is defined like so:</p><pre>public function handleBeginRequest($event)
{
    if (Yii::app()-&gt;user-&gt;isGuest &amp;&amp; !in_array($_GET['r'],array('site/login'))) {
        Yii::app()-&gt;user-&gt;loginRequired();
    }
}</pre><p>The method takes one argument, which will be the event (not actually used in the method). The purpose of the method is to determine the conditions in which a login must be required of the user. That enforcement is made by calling <strong>Yii::app()-&gt;user-&gt;loginRequired()</strong>. For this bare-bones example, the condition checks if the user is a guest, which is to say they aren&#8217;t logged in, and that <strong>$_GET['r'] </strong>does not have a value of <em>site/login</em>. The net effect is that guests can only ever access the login page. If you wanted to allow access to other pages, just add those values to the array:</p><pre>if (Yii::app()-&gt;user-&gt;isGuest &amp;&amp; !in_array($_GET['r'],array('site/login', 'site/index', 'site/contact'))) {
</pre><p>So that&#8217;s one way of implementing a broad login requirement without individually adjusting each Controller. To be clear, you&#8217;ll probably need to do that some as well, like to allow for access to specific actions based upon the type of logged-in user. Still, this is a simple and quite effective catchall. The person that shared the original code in my blog had put all this together within the configuration file. It is possible to do that (by creating an executed function) but the syntax is tricky and the code can really muddle up your configuration file. I think it&#8217;s best to separate it out, plus you now have a new class (<strong>RequireLogin</strong>) that you can use in other Yii-based sites.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2010/07/20/forcing-login-for-all-pages-in-yii/feed/</wfw:commentRss> <slash:comments>52</slash:comments> </item> <item><title>Custom Authentication using the Yii Framework</title><link>http://www.larryullman.com/2010/01/07/custom-authentication-using-the-yii-framework/</link> <comments>http://www.larryullman.com/2010/01/07/custom-authentication-using-the-yii-framework/#comments</comments> <pubDate>Thu, 07 Jan 2010 01:15:18 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[auth]]></category> <category><![CDATA[framework]]></category> <category><![CDATA[mvc]]></category> <category><![CDATA[yii]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=849</guid> <description><![CDATA[In a , I walk through the Yii framework&#8217;s built-in authentication system for adding login functionality to a Web site. There are a number of files and components involved, but simple authentication works fine out of the box, or with just a little tweaking. That&#8217;s the focus of that previous post. In this post, I [...]]]></description> <content:encoded><![CDATA[<p>In a <a
href="http://www.larryullman.com/2010/01/04/simple-authentication-with-the-yii-framework/">previous post</a>, I walk through the <a
href="http://www.yiiframework.com">Yii</a> framework&#8217;s built-in authentication system for adding login functionality to a Web site. There are a number of files and components involved, but simple authentication works fine out of the box, or with just a little tweaking. That&#8217;s the focus of that previous post. In this post, I explain how you can customize the authentication process further.<span
id="more-849"></span>The default authentication behavior allows users to login with hardcoded username/password combinations. In this post, I want to change that behavior so that:</p><ul><li>Authentication is performed against a database table</li><li>The user&#8217;s email address is used instead of their username</li><li>The user&#8217;s ID is stored for later reference</li><li>The user&#8217;s &#8220;role&#8221; is stored for later reference</li></ul><p>To start, let&#8217;s assume there is a database table called <em>User</em> that&#8217;s already been modeled and populated. The table has several columns, including at least: <em>id</em>, <em>email</em>, <em>password</em>, and <em>role</em>. The password column stores a <strong>SHA1()</strong>-encrypted version of the user&#8217;s password. The role dictates what the user can do in the site. Possible values are <em>reader</em>, <em>editor</em>, and <em>writer </em>(these are hypothetical values; they could be anything).</p><p>Now, by default, Yii will use cookies for authentication. In most situations that&#8217;s fine, but if anything of a sensitive nature is being stored, you should use sessions instead. This would apply to both the user&#8217;s ID value and their role. If either is available through a cookie, it wouldn&#8217;t be hard for the user to edit that cookie&#8217;s value in order to become someone else. So, to start, let&#8217;s disable the potential for using cookies. To do that, open up the <strong>protected/config/main.php</strong> configuration file and find this section from under components:</p><pre>'user'=&gt;array(
    // enable cookie-based authentication
    'allowAutoLogin'=&gt;true,
),</pre><p>To disable cookie-based authentication, either remove that code entirely, or change <em>allowAutoLogin</em> to false.</p><p>Next, let&#8217;s turn to the login form, which will require a couple of alterations. Open up <strong>protected/views/site/login.php</strong>, which is the form. The default form looks like this:</p><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_1.png"><img
class="aligncenter size-full wp-image-836" title="Yii Login Form" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_1.png" alt="Yii Login Form" width="582" height="195" /></a></p><p>First, we need to remove the hint paragraph, as demo/demo and admin/admin will no longer work. Then we remove the code that displays the &#8220;remember me&#8221; checkbox. Remember me functionality is only good for cookies, so it&#8217;s useless here. Finally, we want to take an email address, not a username, so those two lines must be changed. The complete form file is now:</p><pre>&lt;?php $this-&gt;pageTitle=Yii::app()-&gt;name . ' - Login'; ?&gt;

&lt;h1&gt;Login&lt;/h1&gt;

&lt;div&gt;
&lt;?php echo CHtml::beginForm(); ?&gt;

&lt;?php echo CHtml::errorSummary($form); ?&gt;

&lt;div&gt;
&lt;?php echo CHtml::activeLabel($form,'email'); ?&gt;
&lt;?php echo CHtml::activeTextField($form,'email') ?&gt;
&lt;/div&gt;

&lt;div&gt;
&lt;?php echo CHtml::activeLabel($form,'password'); ?&gt;
&lt;?php echo CHtml::activePasswordField($form,'password') ?&gt;
&lt;/div&gt;

&lt;div&gt;
&lt;?php echo CHtml::submitButton('Login'); ?&gt;
&lt;/div&gt;

&lt;?php echo CHtml::endForm(); ?&gt;

&lt;/div&gt;&lt;!-- yiiForm --&gt;</pre><p>Next, we turn to the <strong>LoginForm</strong> Model, defined in <strong>protected/models/LoginForm.php</strong>. This Model is associated with the login form, handling and validating that submitted data. At the top of the Model, the class variables are defined. We need to change <strong>$username</strong> to <strong>$email</strong> and remove <strong>$rememberMe</strong>:</p><pre>class LoginForm extends CFormModel
{
    public $email;
    public $password;</pre><p>Next, alter the rules accordingly. Instead of username and password being required, email and password are required. Also, the email value should be in a valid email address format. The application of the <strong>authenticate()</strong> method to validate the password remains. Here are the updated rules:</p><pre>public function rules()
{
    return array(
        array('email, password', 'required'),
        array('email', 'email'),
        array('password', 'authenticate'),
    );
}</pre><p>Next, if you want, change the <strong>attributeLabels()</strong> method for the email address and remove the label for rememberMe:</p><pre>public function attributeLabels()
{
    return array('email'=&gt;'Email Address');
}</pre><p>The final changes to the <strong>LoginForm</strong> Model are in the <strong>authenticate()</strong> method. Several references to username must be changed to email. For example, this:</p><pre>$identity=new UserIdentity($this-&gt;username,$this-&gt;password);</pre><p>becomes:</p><pre>$identity=new UserIdentity($this-&gt;email,$this-&gt;password);</pre><p>Then there&#8217;s a call to <strong>UserIdentity::authenticate()</strong>, which is where the actual authentication against the database takes place (see my previous post and I&#8217;ll also return to this shortly). After that, there&#8217;s an important switch conditional that responds to three possibilities: authenticated, invalid username, and invalid password. The applicable case is signaled by a <strong>UserIdentity</strong> constant. Do note that the <strong>UserIdentity</strong> class is an extension of <strong>CUserIdentity</strong>, so it uses <strong>ERROR_USERNAME_INVALID</strong> instead of <strong>ERROR_EMAIL_INVALID</strong>. In the following code I treat username and email address as synonymous, because it&#8217;s the easiest solution. A full alteration would require changing the Yii framework&#8217;s definition of <strong>CBaseUserIdentity</strong> (which <strong>CUserIdentity</strong> extends), which is not a good idea. So here&#8217;s the modified switch:</p><pre>switch($identity-&gt;errorCode)
{
    case UserIdentity::ERROR_NONE:
        Yii::app()-&gt;user-&gt;login($identity);
        break;
    case UserIdentity::ERROR_USERNAME_INVALID:
        $this-&gt;addError('email','Email address is incorrect.');
        break;
    default: // UserIdentity::ERROR_PASSWORD_INVALID
        $this-&gt;addError('password','Password is incorrect.');
        break;
}</pre><p>In the first case, with no error present, the user is logged in. I&#8217;ve removed references to <em>rememberMe</em> and <em>duration</em>, both of which are present in the Yii-generated code. The second case applies if the email address was not found in the database. Again, the error code is <strong>ERROR_USERNAME_INVALID</strong>, but it applies just the same. We do want to change the error so that it applies to the email element and has the proper error message. The final case applies if the email address was found but the supplied password was incorrect. Here&#8217;s an image for how the login form looks and behaves after these modifications:</p><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_5.png"><img
class="aligncenter size-full wp-image-863" title="Modified Login Form with Errors" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_5.png" alt="Modified Login Form with Errors" width="581" height="255" /></a></p><p>Finally, we turn to <strong>protected/components/UserIdentity.php</strong>, for the final changes. There are a couple of things we need to do in this file. First, we need to perform the authentication against the <strong>User</strong> Model (and therefore, the database). Second, we need to store the user&#8217;s ID and role in the session for later use in the site. For the authentication, we&#8217;ll modify the <strong>authenticate()</strong> method:</p><pre>public function authenticate()
{
    $user = User::model()-&gt;findByAttributes(array('email'=&gt;$this-&gt;username));</pre><p>Now the <strong>$user</strong> object represents the <strong>User</strong> record with an email field equal to the submitted email address. You may be wondering why I refer to <strong>$this-&gt;username</strong> here. That&#8217;s because the <strong>CUserIdentity</strong> class&#8217;s constructor takes the provided email address and password (from <strong>LoginForm</strong>) and stores them in <strong>$this-&gt;username</strong> and <strong>$this-&gt;password</strong>. So I need to equate username with email here, which is better than editing the framework itself. You ought to leave a comment about this so that you won&#8217;t be confused later when looking at the code.</p><p>Next the <strong>authenticate()</strong> method checks a series of possiblities and assigns constant values to the <strong>errorCode</strong> variable:</p><pre>if ($user===null) { // No user found!
    $this-&gt;errorCode=self::ERROR_USERNAME_INVALID;
} else if ($user-&gt;password !== SHA1($this-&gt;password) ) { // Invalid password!
    $this-&gt;errorCode=self::ERROR_PASSWORD_INVALID;</pre><p>In the first conditional, if <strong>$user</strong> has no value, then no records were found, so the email address was incorrect. In the second conditional, the stored password is compared against the <strong>SHA1()</strong> version of the submitted password. This assumes the record&#8217;s password was stored in a <strong>SHA1()</strong>-encrypted format. If neither of these conditionals are true, then everything is okay:</p><pre>} else { // Okay!
    $this-&gt;errorCode=self::ERROR_NONE;
    // Store the role in a session:
    $this-&gt;setState('role', $user-&gt;role);
}</pre><p>As you can see, a constant representing no error is assigned to the error code. After that, the user&#8217;s role value, from the database table, is stored in the session. This is accomplished by invoking the <strong>setState()</strong> method. Provide it with a name, <em>role</em>, and a value. After you&#8217;ve done this, the user&#8217;s role will be available through <strong>Yii::app()-&gt;user-&gt;role</strong>. You could do the same thing to store the user&#8217;s ID in the session, but the built-in authentication already has a <strong>getId()</strong> method that returns the user&#8217;s identifier. By default, the method returns the username value, so you&#8217;ll need to override the default behavior to return the ID instead. Start by creating a private variable in <strong>UserIdentity</strong>:</p><pre>class UserIdentity extends CUserIdentity
{
    // Need to store the user's ID:
    private $_id;</pre><p>Then, in the else clause (for successful authentication), assign the user&#8217;s ID to the class ID variable:</p><pre>$this-&gt;_id = $user-&gt;id;</pre><p>Finally, after the <strong>authenticate()</strong> method, override the <strong>getId()</strong> method by redefining it as:</p><pre>public function getId()
{
    return $this-&gt;_id;
}
</pre><p>Now the user&#8217;s ID will be available through <strong>Yii::app()-&gt;user-&gt;id</strong>.</p><p>And that should be it. You now have an authentication process based upon an email address and password combination, using a database table, that also stores two pieces of information in the session. As always, thanks for reading and let me know if you have any questions or comments. Thanks, Larry!</p><p><strong>Edit: Per a request, here&#8217;s the database schema, the LoginForm.php Model file, and the components/UserIdentity.php script that I *think* I used for this post:</strong></p><pre>CREATE TABLE `User` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `email` varchar(80) NOT NULL,
 `pass` char(40) NOT NULL,
 `role` enum('reader','editor','writer') NOT NULL,
 PRIMARY KEY (`id`)
);
</pre><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/LoginForm.php_.zip">LoginForm.php</a></p><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/UserIdentity.php_.zip">UserIdentity.php</a></p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2010/01/07/custom-authentication-using-the-yii-framework/feed/</wfw:commentRss> <slash:comments>81</slash:comments> </item> <item><title>Simple Authentication with the Yii Framework</title><link>http://www.larryullman.com/2010/01/04/simple-authentication-with-the-yii-framework/</link> <comments>http://www.larryullman.com/2010/01/04/simple-authentication-with-the-yii-framework/#comments</comments> <pubDate>Mon, 04 Jan 2010 15:36:48 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[auth]]></category> <category><![CDATA[framework]]></category> <category><![CDATA[mvc]]></category> <category><![CDATA[yii]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=826</guid> <description><![CDATA[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&#8217;s authentication system first. And, as happens with me, in writing about that, and how [...]]]></description> <content:encoded><![CDATA[<p>I wanted to write up a strong post on Access Control Lists in <a
href="http://www.yiiframework.com">Yii</a>, 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&#8217;s authentication system first. And, as happens with me, in writing about that, and how you would <a
href="http://www.larryullman.com/2010/01/07/custom-authentication-using-the-yii-framework/">customize the authentication process</a>, I had to break the subject down into two posts. So here&#8217;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&#8217;s authentication system work together; much of what I say in this first post is also available in the Yii <a
href="http://www.yiiframework.com/doc/">documentation</a>, just not presented in this way. I also show a couple of quick ways to modify its behavior to suit your situation.<span
id="more-826"></span></p><p>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&#8217;s command-line tools, three files for managing authentication are created:</p><ul><li><strong>protected/components/UserIdentity.php</strong></li><li><strong>protected/models/LoginForm.php</strong></li><li><strong>protected/views/site/login.php</strong></li></ul><p>And there&#8217;s also some code added to <strong>protected/controllers/SiteController.php</strong> that comes into play. The Controller file, gets the action going, of course. The View file is the login form itself. The <strong>LoginForm</strong> Model file defines the rules and behavior and the <strong>UserIdentity</strong> file defines a Model that performs the actual authentication.</p><p>By default, if you do nothing at all, users will be allowed to log into the site using the username/password combinations of <em>demo</em>/<em>demo</em> or <em>admin</em>/<em>admin</em>. These values are set in the <strong>UserIdentity.php</strong> script. If all you need to do is allow only a single authenticated user, then you can open <strong>UserIdentity.php</strong> and change this code:</p><pre class="brush: php; title: ; notranslate">$users=array(
    // username =&gt; password
    'demo'=&gt;'demo',
    'admin'=&gt;'admin',
);</pre><p>to</p><pre class="brush: php; title: ; notranslate">$users=array(
    'whateverName'=&gt;'whateverPassword'
);</pre><p>At that point, you&#8217;re done. However, you most likely will perform authentication against a database table, so let&#8217;s see how you&#8217;d edit these files to make that happen. To start, let&#8217;s assume that the table name is <em>Users</em>, that you&#8217;ve already generated a Model for it, and that authentication requires an username and a password. As you&#8217;ll see, you&#8217;ll still only need to edit the <strong>UserIdentity.php</strong> file to make this possible, but in my next post I&#8217;ll walk through more elaborate customizations. Okay, with that in mind, let&#8217;s examine the authentication process&#8230;</p><p>The URL to login will likely be <span
style="text-decoration: underline;">www.example.com/index.php/site/login</span>, 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&#8217;ll go through the Site Controller and call the <strong>actionLogin()</strong> method. That method is defined as:</p><pre class="brush: php; title: ; notranslate">public function actionLogin()
{
    $form=new LoginForm;
    // collect user input data
    if(isset($_POST['LoginForm']))
    {
        $form-&gt;attributes=$_POST['LoginForm'];
        // validate user input and redirect to previous page if valid
        if($form-&gt;validate()  &amp;&amp; $form-&gt;login()) $this-&gt;redirect(Yii::app()-&gt;user-&gt;returnUrl);
    }
    // display the login form
    $this-&gt;render('login',array('form'=&gt;$form));
}</pre><p>First, a new object is created of type <em>LoginForm</em>. That class is defined in the <strong>LoginForm.php</strong> 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 <strong>LoginForm</strong> object. The default login form looks like this (note the reference to demo/demo and admin/admin, already discussed):</p><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_1.png"><img
class="aligncenter size-full wp-image-836" title="Yii Login Form" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_1.png" alt="Yii Login Form" width="582" height="195" /></a></p><p>Now, the call to the <strong>validate()</strong> method in the above code means that the form data has to pass the validation rules established in the <strong>LoginForm</strong> class. This is basic Model validation as defined by the <strong>rules()</strong> method of the Model (also see <a
href="http://www.larryullman.com/2009/11/10/basic-model-edits-in-yii/">my post on basic Model edits</a>):</p><pre class="brush: php; title: ; notranslate">public function rules()
{
    return array(
        // username and password are required
        array('username, password', 'required'),
        // password needs to be authenticated
        array('password', 'authenticate'),
    );
}</pre><p>As you can see, those rules say that both the username and password are required and that the password has to pass the <strong>authenticate()</strong> method. This is not a built-in validation routine, but is defined in <strong>LoginForm</strong>. The <strong>LoginForm::</strong><strong>authenticate()</strong> method starts off like so:</p><pre class="brush: php; title: ; notranslate">public function authenticate($attribute,$params)
{
    if(!$this-&gt;hasErrors())  // we only want to authenticate when no input errors
    {
        $identity=new UserIdentity($this-&gt;username,$this-&gt;password);
        $identity-&gt;authenticate();
        switch($identity-&gt;errorCode)</pre><p>If there are no errors when this method is called (an error would be a lack of a username or password), a <strong>UserIdentity</strong> object is created, passing that object the submitted username and password. Then the <strong>UserIdentity</strong> object&#8217;s <strong>authenticate()</strong> method is called. This gets us to <strong>protected/components/UserIdentity.php</strong>, which defines the class and the method. If you&#8217;re having trouble following the process thus far, here it is pictorially:</p><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_2.png"><img
class="aligncenter size-full wp-image-840" title="Yii Auth Process" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_2.png" alt="Yii Auth Process" width="451" height="361" /></a></p><p>Note that any errors stops the process from continuing and just re-displays the login form, with the errors reported.</p><p>As I already wrote above, the <strong>UserIdentity</strong> <strong>authenticate()</strong> 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&#8217;ll need to add some code. Start by fetching the record for the given username:</p><pre class="brush: php; title: ; notranslate">class UserIdentity extends CUserIdentity
{
    public function authenticate()
    {
        $user = User::model()-&gt;findByAttributes(array('username'=&gt;$this-&gt;username));
</pre><p>Now the <strong>$user</strong> object represents the <strong>User</strong> record with an username field equal to the submitted username. (The <strong>CUserIdentity</strong> class&#8217;s constructor takes the provided username and password and stores them in <strong>$this->username</strong> and <strong>$this->password</strong>, 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&#8217;t be able to provide more meaningful error messages: username doesn&#8217;t exist, username does exist but the password doesn&#8217;t match, and so forth.</p><p>Next the <strong>authenticate()</strong> method should check a series of possiblities and assigns constant values to the <strong>errorCode</strong> variable:</p><pre class="brush: php; title: ; notranslate">if ($user===null) { // No user found!
    $this-&gt;errorCode=self::ERROR_USERNAME_INVALID;
} else if ($user-&gt;pass !== SHA1($this-&gt;password) ) { // Invalid password!
    $this-&gt;errorCode=self::ERROR_PASSWORD_INVALID;</pre><p>In the first conditional, if <strong>$user</strong> has no value, then no records were found, so the username was incorrect. In the second conditional, the stored password is compared against the <strong>SHA1()</strong> version of the submitted password. This assumes the record&#8217;s password was stored in a <strong>SHA1()</strong> encrypted format. If neither of these conditionals are true, then everything is okay:</p><pre class="brush: php; title: ; notranslate">} else { // Okay!
    $this-&gt;errorCode=self::ERROR_NONE;
}</pre><p>Finally, the method returns a boolean value, indicating an error or not:</p><pre class="brush: php; title: ; notranslate">return !$this-&gt;errorCode;</pre><p>The presence of an error code gets used in the <strong>authenticate()</strong> method of the <strong>LoginForm</strong> Model, in response to the authentication attempt (this is a continuation of the <strong>LoginForm::authenticate()</strong> code shown above):</p><pre class="brush: php; title: ; notranslate">$identity-&gt;authenticate();
switch($identity-&gt;errorCode)
{
    case UserIdentity::ERROR_NONE:
        $duration=$this-&gt;rememberMe ? 3600*24*30 : 0; // 30 days
        Yii::app()-&gt;user-&gt;login($identity,$duration);
        break;
    case UserIdentity::ERROR_USERNAME_INVALID:
        $this-&gt;addError('username','Username is incorrect.');
        break;
    default: // UserIdentity::ERROR_PASSWORD_INVALID
        $this-&gt;addError('password','Password is incorrect.');
        break;
}</pre><p>So if there was no error, the user is logged in. The <em>duration</em>—the period for which they&#8217;ll be logged in—is either 30 days or for just the session, depending upon whether they checked the <strong>rememberMe</strong> box or not (see the login form image). If either error is present, it&#8217;ll be added to the current object, the validation will fail, meaning that the conditional in the <strong>actionLogin()</strong> method of <strong>SiteController.php</strong> will be false, and the login form will be rendered again, this time with the error message. The whole process therefore becomes:</p><p><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_3.png"><img
class="aligncenter size-full wp-image-841" title="Yii Auth Process, Complete" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/01/yii_auth_3.png" alt="Yii Auth Process, Complete" width="447" height="354" /></a></p><p>That&#8217;s an outline of the basic process, using a <strong>User</strong> 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:</p><ul><li>Store the user&#8217;s ID so it can be referenced as they peruse the site</li><li>Store the user&#8217;s &#8220;role&#8221;, like reader, editor, and writer, as well.</li><li>Authenticate the user with their email address and password, not their username.</li></ul><p>That post will follow in just a couple of days. EDIT: <a
href="http://www.larryullman.com/2010/01/07/custom-authentication-using-the-yii-framework/">Here it is</a>! 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</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2010/01/04/simple-authentication-with-the-yii-framework/feed/</wfw:commentRss> <slash:comments>39</slash:comments> </item> </channel> </rss>
<!-- Served from: www.larryullman.com @ 2012-02-05 16:10:36 by W3 Total Cache -->
