Jump to content
Larry Ullman's Book Forums

Custom Authentication Using The Yii Framework


Raymien
 Share

Recommended Posts

Hello boys and girls,

 

I've been looking at a way to maintain access to the user name when using the Custom Authentication by email, as explained in the book.

 

I think logging in via email is a good idea, as I still have members to our Curling site, who are quite forgetful of their usernames, but email's tend to not change.  That being said, I've got at least one player who has actually gotten himself 3 different user accounts, because he forgets his username.

 

On the flip side, many folks like to be called by their names, be it a pseudonym, or their actual name, rather than johnny274@gmail.com.

 

So I tried what I thought would work, by setting the username much in the same way as the id as shown in the book.  It didn't work.

 

Then I noticed in the blog, a commenter asked a similar question (Josh) and found a solution that worked for him.  Which was surprising similar to what I thought would work.  So I tried that, and it still didn't work.  So obviously I'm missing something.  To note, I have been coding for many years now, longer than I care to admit, but I'm kinda new to the Yii framework, so please be gentle!

 

Here's the code: UserIdentity

 

private $_name;
.
.
.
//within the authenticate function
$this->_name = $user->username;
.
.
.
public function getUsername(){
  return $this->_name;
}

 

I'm sure you'll all laugh and say, "That's obvious!" and after I read it, I'll smack myself in the head for missing it, but anyway. :-)

 

Thanks,

 

Ray

 

Link to comment
Share on other sites

There's nothing obviously wrong in this little snippet of code. It depends upon what $user is, whether $user->username has a value, and how the getUsername() method is being called. It looks like you're on the right track, however.

Link to comment
Share on other sites

  • 2 weeks later...

Maybe I should step back a bit, and trace the login process, which starts with LoginForm:

 

$this->_identity=new UserIdentity($this->username,$this->password);
//becomes
$this->_identity=new UserIdentity($this->email,$this->password);

 

UserIdentity is the component which incorporates the new db authenticate function, and Larry clearly shows/reminds us that email is now username.

 

// Understand that email === username 
$user = User::model()->findByAttributes(array('email'=>$this->username));

Now, if I understand correctly, $user is the local variable accessing the user model ($user = User::model()), and that if I want $user to include username, I'd need to modify the model.

 

That's the part I'm confused about.

 

(sorry if I seem to be rambling, I'm trying to sort through this again in my head.)

 

Maybe it would be easier to just query the db to get the proper username that matches the email, and construct the User with that, then validate the password?

 

Push me in the right direction please, I think I'm starting to get a headache. :)

 

Ray

Link to comment
Share on other sites

These parts of code can get complicated. Actually you don't need to alter the model because username is already available via $this->username in UserIdentity because

 

$this->_identity=new UserIdentity($this->username,$this->password);

 

as you can see in the above code snipet, the username and password were already passed to the UserIdentity class on its creation in public function login().

 

class UserIdentity extends CUserIdentity 'This is worth looking at in more detail'

 

Okay now we are in CUserIdentity below you can see the public $username and $password

class CUserIdentity extends CBaseUserIdentity
{
    /**
     * @var string username
     */
    public $username;
    /**
     * @var string password
     */
    public $password;

    /**
     * Constructor.
     * @param string $username username
     * @param string $password password
     */
    public function __construct($username,$password)
    {
        $this->username=$username;
        $this->password=$password;
    }

So in your userIdentity class something basic like this will do the trick

class UserIdentity extends CUserIdentity
{
	private $_id;
	 
	public function authenticate()
	{
		// Load model for username and email by active record		
		$user = User::model()->findByAttributes(array('username'=>$this->username));
		
		if($user === null)
            $this->errorCode=self::ERROR_USERNAME_INVALID;
		else if($user->password !== hash_hmac('sha256', $this->password, Yii::app()->params['encryptionKey']))
			$this->errorCode=self::ERROR_PASSWORD_INVALID;		
		else
		{
			$this->errorCode = self::ERROR_NONE;
			$this->_id = $user->id;
		}
        
		return !$this->errorCode;
	}
	
	public function getId()
    {
        return $this->_id;
    }
}

I hope this helps you get the picture, it took me a while to work that part out myself.

Link to comment
Share on other sites

You could authenticate email with your statement if email was passed in place of username

$user = User::model()->findByAttributes(array('email'=>$this->username));

That statement seems valid to me.

 

If you wanted to find username you would only then need to do this

$username = $user->username; (After you run your above statement)

Because you have already received the user record from the email instead.

 

Take into account if you do this you would need to change UserIdentity.php. I would also override the contructor of UserIdentity.php and change to take in parameters $email and $password as apposed to $username and $password.

Link to comment
Share on other sites

 Share

×
×
  • Create New...