Activate captcha after unsuccessful login attempts

You are viewing revision #4 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.

« previous (#3)next (#5) »

Like gmail, if you have tree or more unsuccessful login attemps a captcha appears

But, how to do this with Yii ?

Modify your login Model like that

class LoginForm extends CFormModel {
	 ....
	 public $verifyCode;
	 
	 public function rules() {
        return array(
            array('username, password', 'required'),
            array('rememberMe', 'boolean'),
            array('password', 'authenticate'),
            array('verifyCode', 'captcha', 'allowEmpty' => !CCaptcha::checkRequirements(), 'on' => 'withCaptcha'), //only on withCaptcha scenario
        );
    ....

In your controller

public function actionLogin() {
        
        $model = new LoginForm;
        if (Yii::app()->user->getState('attempts-login') > 3) { //make the captcha required if the unsuccessful attemps are more of thee
            $model->scenario = 'withCaptcha';
        }
		
        if (isset($_POST['LoginForm'])) {
            $model->attributes = $_POST['LoginForm'];

            if ($model->validate() && $model->login()) {
                Yii::app()->user->setState('attempts-login', 0); //if login is successful, reset the attemps
                $this->controller->redirect(Yii::app()->user->returnUrl);
            } else {  //if login is not successful, increase the attemps 
                Yii::app()->user->setState('attempts-login', Yii::app()->user->getState('attempts-login', 0) + 1);

                if (Yii::app()->user->getState('attempts-login') > 3) { 
                    $model->scenario = 'withCaptcha'; //useful only for view
                }
            }
        }
        
        $this->render('login', array('model' => $model));
    }
Finally in your view login add this to the form


<?php if ($model->scenario == 'withCaptcha' && CCaptcha::checkRequirements()): ?>
            <div class="row">
                <?php echo $form->labelEx($model, 'verifyCode'); ?>
                <div>
                    <?php $this->widget('CCaptcha'); ?>
                    <?php echo $form->textField($model, 'verifyCode'); ?>
                </div>
                <?php echo $form->error($model, 'verifyCode'); ?>
            </div>
        <?php endif; ?>