What do you think about changing the instances of 'username' in the auth component to something more generic like 'account'. Username just seems so specific. like i use my username 'jayrulez' to log on to this forum, but not all applications use username for authentication but email, phone #s etc... using account wouldn't be as specific as username as account can be represented by id, username, email and much more. How about this for Yii?
Page 1 of 1
Idea for auth
#1
Posted 07 October 2009 - 02:20 PM
php: foreach(array('cat', 'dog', 'cow') as $animal) echo $animal."\n"; python: [(animal, print(animal)) for animal in ['cat', 'dog', 'cow']] ruby: ['cat', 'dog', 'cow'].each {|animal| puts animal}
You say Tomato, I say Tomato.
#2
Posted 08 October 2009 - 03:54 AM
In Web3CMS we thought about we same, and created a way to log in with either "Username" or "Email" or "Username or email". This is configured in params.php with
Then in login view we add activeHiddenField($form,'loginWithField') to understand what is the account field, and activeTextField($form,$form->getLoginWithField()) to display the account field itself.
Then in UserLoginModel we read the account field and pass it to _CUserIdentity component, which is validating user input agains User db-table according to the account field.
Web3CMS is open source, feel free to download it and try (link is in the bottom).
Listing of user login view:
Listing of UserLoginForm model:
Listing of _CUserIdentity component:
// which field to log user in with. possible values: username/email/_any_ // reset this on any page with MParams::setUserLoginWithField('username'); 'userLoginWithField'=>'username', //'username'
Then in login view we add activeHiddenField($form,'loginWithField') to understand what is the account field, and activeTextField($form,$form->getLoginWithField()) to display the account field itself.
Then in UserLoginModel we read the account field and pass it to _CUserIdentity component, which is validating user input agains User db-table according to the account field.
Web3CMS is open source, feel free to download it and try (link is in the bottom).
Listing of user login view:
<?php MParams::setPageLabel(Yii::t('page','Login')); ?> <?php MUserFlash::setTopError(_CHtml::errorSummary($form)); ?> <?php MUserFlash::setSidebarInfo(Yii::t('feedback','Hint: You may login with <tt>demo/demo</tt> or <tt>admin/admin</tt>.')); ?> <?php $this->widget('application.components.WContentHeader',array( 'breadcrumbs'=>array( array( 'url'=>CHtml::normalizeUrl(array($this->getAction()->getId())), 'active'=>true ), ), )); ?> <div class="w3-main-form-wrapper ui-widget-content ui-corner-all"> <?php echo _CHtml::beginForm('','post',array('class'=>'w3-main-form'))."\n"; ?> <?php echo _CHtml::activeHiddenField($form,'loginWithField')."\n"; ?> <div class="w3-form-row w3-first"> <div class="w3-form-row-label"><?php echo _CHtml::activeLabelEx($form,$form->getLoginWithField()); ?></div> <div class="w3-form-row-input"> <?php echo _CHtml::activeTextField($form,$form->getLoginWithField(),array('class'=>'w3-input-text ui-widget-content ui-corner-all'))."\n"; ?> </div> <div class="clear"> </div> </div> <div class="w3-form-row"> <div class="w3-form-row-label"><?php echo _CHtml::activeLabelEx($form,'password'); ?></div> <div class="w3-form-row-input"> <?php echo _CHtml::activePasswordField($form,'password',array('class'=>'w3-input-text ui-widget-content ui-corner-all','maxlength'=>64))."\n"; ?> </div> <div class="clear"> </div> </div> <?php if(Yii::app()->user->allowAutoLogin): ?> <div class="w3-form-row"> <div class="w3-form-row-label"> </div> <div class="w3-form-row-input"> <div class="w3-form-row-text"> <?php echo _CHtml::activeCheckBox($form,'rememberMe')."\n"; ?> <?php echo _CHtml::activeLabelEx($form,'rememberMe')."\n"; ?> </div> </div> <div class="clear"> </div> </div> <?php endif; ?> <div class="w3-form-row"> <div class="w3-form-row-label"> </div> <div class="w3-form-row-input"> <?php echo _CHtml::submitButton(Yii::t('link','Log in'),array('class'=>'w3-input-button ui-button ui-state-default ui-corner-all'))."\n"; ?> </div> <div class="clear"> </div> </div> <?php echo _CHtml::endForm(); ?> </div><!-- w3-main-form-wrapper --> <?php MClientScript::registerScript('focusOnFormFirstItem'); ?> <?php MClientScript::registerScript('w3FormButton'); ?>
Listing of UserLoginForm model:
<?php /** * UserLoginForm class. * UserLoginForm is the data structure for keeping * user login form data. It is used by the 'login' action of 'UserController'. */ class UserLoginForm extends CFormModel { public $email; public $password; public $rememberMe; public $username; public $usernameOrEmail; public static $loginWithField; public function __construct($attributes=array(),$scenario='') { parent::__construct($attributes,$scenario); self::$loginWithField=$this->getLoginWithField(); } /** * 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 or email or usernameOrEmail is required array(self::getLoggingWithField(), 'required'), // password is required array('password', 'required'), // password needs to be authenticated array('password', 'authenticate'), ); } /** * Declares the attribute labels. * If an attribute is not delcared here, it will use the default label * generation algorithm to get its label. */ public function attributeLabels() { return array( 'rememberMe'=>Yii::t('feedback','Remember my member account on this computer'), 'password'=>Yii::t('t','Password'), 'username'=>Yii::t('t','Username'), 'usernameOrEmail'=>Yii::t('t','Username or email'), ); } /** * 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 _CUserIdentity($this->{self::getLoggingWithField()},$this->password); $identity->authenticate(); switch($identity->errorCode) { case _CUserIdentity::ERROR_NONE: // if user is already logged in if(!Yii::app()->user->isGuest) { // log user out from the current account. i want to sleep well, do you? ;) Yii::app()->user->logout(); if(!Yii::app()->getSession()->getIsStarted()) // restore http session. this is necessary for login Yii::app()->getSession()->open(); } // remember for 30 days. makes sence only if auto-login is allowed $duration=(Yii::app()->user->allowAutoLogin && $this->rememberMe) ? 3600*24*30 : 0; // log user in and save in session all appended data Yii::app()->user->login($identity,$duration); // set user preferences (for welcome message, and so on) if(isset(Yii::app()->user->interface) && !empty(Yii::app()->user->interface)) // set user preferred interface W3::setInterface(Yii::app()->user->interface); if(isset(Yii::app()->user->language) && !empty(Yii::app()->user->language)) // set user preferred language W3::setLanguage(Yii::app()->user->language); break; case _CUserIdentity::ERROR_USERNAME_INVALID: if(self::getLoggingWithField()==='username') $this->addError('username',Yii::t('t','Username is incorrect.')); else if(self::getLoggingWithField()==='email') $this->addError('email',Yii::t('t','Email is incorrect.')); else if(self::getLoggingWithField()==='usernameOrEmail') $this->addError('usernameOrEmail',Yii::t('t','Username or email is incorrect.')); break; case _CUserIdentity::ERROR_ACCOUNT_IS_INACTIVE: // set the error message MUserFlash::setTopError(Yii::t('feedback', 'We are sorry, but your member account is marked as "inactive". Inactive member accounts are temporarely inaccessible. {contactLink}.', array('{contactLink}'=>CHtml::link(Yii::t('link','Contact us'),array('site/contact'))) )); // add to username (first field in the login form) error css class // and make the validate() to fail $attribute=self::getLoggingWithField(); $attribute!=='username' && $attribute!=='email' && $attribute!=='usernameOrEmail' && ($attribute='username'); $this->addError($attribute,''); break; case _CUserIdentity::ERROR_IS_NOT_ADMINISTRATOR: // set the error message MUserFlash::setTopError(Yii::t('feedback', 'We are sorry, but your access type is {accessType}. Required access type: {requiredAccessType}.', array( '{accessType}'=>Yii::app()->controller->var->userAccessType, '{requiredAccessType}'=>Yii::t('t',User::ADMINISTRATOR_T) ) )); unset(Yii::app()->controller->var->userAccessType); // we do not need this any more // add to username (first field in the login form) error css class // and make the validate() to fail $attribute=self::getLoggingWithField(); $attribute!=='username' && $attribute!=='email' && $attribute!=='usernameOrEmail' && ($attribute='username'); $this->addError($attribute,''); break; case _CUserIdentity::ERROR_PASSWORD_INVALID: default: $this->addError('password',Yii::t('t','Password is incorrect.')); break; } } } /** * Which field to log user in with * * @return string */ public function getLoginWithField() { $array=array( 'username'=>'username', 'email'=>'email', '_any_'=>'usernameOrEmail' ); return $array[MParams::getUserLoginWithField()]; } /** * Which field is user now trying to login with * If trying to login with username, but later userLoginWithField param * was changed to email, still username should be required, not email, right? * * @return string */ public static function getLoggingWithField() { switch(self::$loginWithField) { case 'username': case 'email': case 'usernameOrEmail': return self::$loginWithField; break; default: return 'username'; break; } } }
Listing of _CUserIdentity component:
<?php /** * _CUserIdentity represents the data needed to identity a user. * It contains the authentication method that checks if the provided * data can identity the user. */ class _CUserIdentity extends CUserIdentity { const ERROR_UNKNOWN_IDENTITY=10; const ERROR_ACCOUNT_IS_INACTIVE=11; const ERROR_IS_NOT_ADMINISTRATOR=12; private $_id; /** * @return integer the ID of the user record */ public function getId() { return $this->_id; } /** * Authenticates a user. * @return boolean whether authentication succeeds. */ public function authenticate() { if(UserLoginForm::getLoggingWithField()=='username') $user=User::model()->findByAttributes(array('username'=>$this->username)); else if(UserLoginForm::getLoggingWithField()=='email') $user=User::model()->findByAttributes(array('email'=>$this->username)); else if(UserLoginForm::getLoggingWithField()=='usernameOrEmail') $user=User::model()->find("`username`=? OR `email`=?",array($this->username,$this->username)); if($user===null) $this->errorCode=self::ERROR_USERNAME_INVALID; else if(md5($this->password)!==$user->password) $this->errorCode=self::ERROR_PASSWORD_INVALID; else if($user->isActive===User::IS_NOT_ACTIVE) $this->errorCode=self::ERROR_ACCOUNT_IS_INACTIVE; else if(MArea::isBackend() && !User::isAdministrator($user->accessType)) { $this->errorCode=self::ERROR_IS_NOT_ADMINISTRATOR; Yii::app()->controller->var->userAccessType=$user->getAttributeView('accessType'); } else { $this->_id=$user->id; $this->errorCode=self::ERROR_NONE; // do not store password or other sensitive data in the persistent storage // when (config/main.php) allowAutoLogin is true, because // all these data will be stored in cookie = it is readable $this->setState('email', $user->email); $this->setState('interface', $user->interface); $this->setState('language', $user->language); $this->setState('screenName', $user->screenName); } return !$this->errorCode; } /** * Authenticates a user by cookie. * Is called by {@link _CWebUser::restoreFromCookie()}. * @return boolean whether authentication succeeds. */ public function authenticateByCookie() { $user=User::model()->findByPk($this->username); if($user===null) $this->errorCode=self::ERROR_UNKNOWN_IDENTITY; else if($user->isActive==='0') $this->errorCode=self::ERROR_ACCOUNT_IS_INACTIVE; else { $this->_id=$user->id; $this->errorCode=self::ERROR_NONE; // do not store password or other sensitive data in the persistent storage // when (config/main.php) allowAutoLogin is true, because // all these data will be stored in cookie = it is readable $this->setState('email', $user->email); $this->setState('interface', $user->interface); $this->setState('language', $user->language); $this->setState('screenName', $user->screenName); } return !$this->errorCode; } }
Share this topic:
Page 1 of 1