Developing login, but with EMAIL, instead of USERNAME

Hi,

I want to use EMAIL as USERNAME by using UserIdentity. Is the best way to generate my own Login or to use the default one with changed UserIdentity class?

Because, if I want to use it with UserIdenity, I must change the frawework's class "CUserIdentity", which I don't want to do.

What do you suggest?

Of course you shouldn't modify CUserIdentity.

You can modify UserIdentity by changing its constructor so that it takes email and password as parameters. You will need to override getName() method to return the username associated with that email.

Qiang, I have this now:



<?php





/**


 * UserIdentity represents the data needed to identity a user.


 * It contains the authentication method that checks if the provided


 * data can identity the user.


 */


class UserIdentity extends CUserIdentity


{


	


		public $EMAIL;


	   public $PASSWORD;


	


		public function __construct($email, $password)


	{


		$this->EMAIL= $email;


		$this->PASSWORD = $password;


	}


	


	


	public function getName(){


		return $this->EMAIL;


	}





	


	/**


	 * Authenticates a user.


	 * The example implementation makes sure if the username and password


	 * are both 'demo'.


	 * In practical applications, this should be changed to authenticate


	 * against some persistent user identity storage (e.g. database).


	 * @return boolean whether authentication succeeds.


	 */


	public function authenticate()


	{


		/*


		$users=array(


			// username => password


			'demo'=>'demo',


			'admin'=>'admin',


		);


		*/


		


		$users = users::model()->findAll();


		


		//print var_dump(isset($users[$this->EMAIL]));


		


		//print_r($users);


		


		if(!isset($users[$this->EMAIL]))


			$this->errorCode=self::ERROR_USERNAME_INVALID;


		else if($users[$this->EMAIL]!==$this->PASSWORD)


			$this->errorCode=self::ERROR_PASSWORD_INVALID;


		else


			$this->errorCode=self::ERROR_NONE;


		return !$this->errorCode;


	}


}




<?php





/**


 * LoginForm class.


 * LoginForm is the data structure for keeping


 * user login form data. It is used by the 'login' action of 'SiteController'.


 */


class LoginForm extends CFormModel


{


	public $EMAIL;


	public $PASSWORD;


	public $rememberMe;


	





	/**


	 * Declares the validation rules.


	 * The rules state that username and password are required,


	 * and password needs to be authenticated.


	 */


	public function rules()


	{


		return array(


			// username and password are required


			array('EMAIL, PASSWORD', 'required'),


			// password needs to be authenticated


			array('PASSWORD', 'authenticate'),


		);


	}





	/**


	 * Authenticates the password.


	 * This is the 'authenticate' validator as declared in rules().


	 */


	public function authenticate($attribute,$params)


	{


		if(!$this->hasErrors())  // we only want to authenticate when no input errors


		{


			


			


			$identity=new UserIdentity($this->EMAIL,$this->PASSWORD);


			$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('EMAIL','EMAIL is incorrect.');


					break;


				default: // UserIdentity::ERROR_PASSWORD_INVALID


					$this->addError('PASSWORD','Password is incorrect.');


					break;


			}


		}


	}


}





Actually, it says that Email is incorrect with the custom message, but the check consists of checking which constant is enabled in the model like this:



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('EMAIL','EMAIL is incorrect.');


					break;


				default: // UserIdentity::ERROR_PASSWORD_INVALID


					$this->addError('PASSWORD','Password is incorrect.');


					break;


Any ideas?

Your UserIdentity::authenticate() is not correct.

First, you should not call findAll() to get all users. This is not practical in large systems.

Second, even for small systems, the $users array is not indexed by email. Please check the blog demo for an example on how to authenticate against database.

Other code are fine.

Qiang, I made it this way, after taking a look on the approach you've used in the blog demo.



public function authenticate()


	{


		/*


		$users=array(


			// username => password


			'demo'=>'demo',


			'admin'=>'admin',


		);


		*/


		


				$users=Users::model()->find('LOWER(EMAIL)=?',array(strtolower($this->EMAIL)));


				


		if($users === null)


			$this->errorCode=self::ERROR_USERNAME_INVALID;


		else if(($this->PASSWORD)!==$users->PASSWORD)


			$this->errorCode=self::ERROR_PASSWORD_INVALID;


		else


		{


			$this->_ID=$users->USER_ID;


			$this->EMAIL=$users->EMAIL;


			$this->setState("EMAIL", $this->EMAIL);


			$this->errorCode=self::ERROR_NONE;


		}


		return !$this->errorCode;


	}





}


In fact, it works, I am getting "Welcome email@email.test".

The problem is that when I visit the next module, which requires the user to be authenticated, I am getting the login form again. Also, at the top menu, I don't see Logout, despite the fact there is a welcome message.

Is there any variable I have to set? Also, how do a specify the type of user -> user, admin?

You need to override getId() as well because the default implementation simply returns username (in your case, it is null).

To store user type, please refer to http://www.yiiframew…doc/cookbook/6/

Yes, Qiang, this was the issue, but I couldn't reply last evening. Thanks!