Form submission after session has expired

There exists a circumstance where the user will submit a form after his/her session has expired.

By simply redirecting the user to the login page, you will be sure to loose the user’s confidence in your app, since it will destroy all the input he/she has written so far.

A longer expiration time of session might be a quick solution, but it’s not always applicable.

How can I re-authenticate the user when he/she has submitted a form after the session has expired? Is there any good assistance in Yii 2?

[EDIT]

To be more precise, I would like to do the following:

  1. Check if the user is still logged in just before the form submission.

  2. If he/she is, then there’s no problem: go submitting.

  3. If he/she is not, pop up a modal login form to re-login.

  4. On successful login, continue with the form submission.

I would appreciate any suggestions. Thanks.

So, this is what I finally got:

The main form that is very long and time-consuming




...

<?php

// renders the ajax login form at the end of the form script

echo $this->render('//site/_ajax_login', [

    'mainFormId' => 'very-long-and-time-consuming-form',  // id of the main form

]);



The ajax login form ‘site/_ajax_login.php’




<?php


use yii\helpers\Html;

use yii\bootstrap\ActiveForm;

use app\models\LoginForm;

use yii\bootstrap\Modal;


/* @var $this yii\web\View */

/* @var $form yii\bootstrap\ActiveForm */

/* @var $mainFormId string */


$model = new LoginForm();

if (!Yii::$app->user->isGuest) {

    $model->username = Yii::$app->user->identity->username; // username for login credential

}

?>


<?php Modal::begin([

    'header' => 'Re-enter your password',

    'toggleButton' => false,

    'id' => 'ajax-login-modal',

    'size' => Modal::SIZE_DEFAULT,

]); ?>


    <?php $form = ActiveForm::begin([

        'id' => 'ajax-login-form',

        'action' => ['/site/ajax-login'],

        'options' => ['class' => 'form-horizontal'],

        'fieldConfig' => [

            'template' => "{label}\n<div class=\"col-sm-3 col-xs-8\">{input}</div>",

            'labelOptions' => ['class' => 'col-sm-3 col-xs-4 control-label'],

        ],

    ]); ?>


    <?= $form->field($model, 'username')->textInput(['readonly' => true]) ?>

    <?= $form->field($model, 'password')->passwordInput() ?>

    <div class="form-group">

        <div class="col-sm-offset-3 col-sm-3 col-xs-offset-4 col-xs-8">

            <?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>

        </div>

    </div>


    <?php ActiveForm::end(); ?>


<?php Modal::end();


$checkUrl = Yii::$app->urlManager->createUrl(['/site/login-check']);

$loginUrl = Yii::$app->urlManager->createUrl(['/site/ajax-login']);


$this->registerJs("

var loginchecked = false;

$('#$mainFormId').on('beforeValidate', function(event, messages, deferreds){

    if (!loginchecked) {

        $.post('$checkUrl','', function(data){

            if (data === 'user') {

                doSubmit();

            } else {

                loginModal = true;

                $('#ajax-login-modal').modal('show');

            }

        }, 'json');

        return false;

    } else {

        return;

    }

});


function doSubmit() {

    loginchecked = true;

    setTimeout(function(){

        loginchecked = false;

    }, 1000);

    $('#$mainFormId').submit();

}


$('#ajax-login-form').on('beforeValidate', function(event, messages, deferreds) {

    $.post('$loginUrl',$(this).serialize(), function(data){

        if (data === 'user') {

            $('#ajax-login-modal').modal('hide');

            doSubmit();

        } else {

            alert('Wrong password.');

        }

    }, 'json');

    return false;

});

");



SiteController




...

    public function behaviors()

    {

        return [

            'access' => [

                'class' => AccessControl::className(),

                'only' => ['logout'],

                'rules' => [

                    [

                        'actions' => ['logout'],

                        'allow' => true,

                        'roles' => ['@'],

                    ],

                ],

            ],

            'verbs' => [

                'class' => VerbFilter::className(),

                'actions' => [

                    'logout' => ['post'],

                    'login-check' => ['post'],

                    'ajax-login' => ['post'],

                ],

            ],

        ];

    }

...


...

    public function actionLoginCheck()

    {

        $response = Yii::$app->response;

        $response->format = \yii\web\Response::FORMAT_JSON;

        $response->data = Yii::$app->user->isGuest ? 'guest' : 'user';

    }


    public function actionAjaxLogin()

    {

        $response = Yii::$app->response;

        $response->format = \yii\web\Response::FORMAT_JSON;


        $model = new LoginForm();

        if ($model->load(Yii::$app->request->post()) && $model->login()) {

            $response->data = 'user';

        } else {

            $response->data = 'guest';

        }

    }

...



It seems working fine, at least for the moment.

At first I was trying to use on.(‘submit’, function(){}) and got confused by a strange behavior of the ActiveForms.

By replacing it with on.(‘beforeValidate’, function(){}) I got the expected result.

Please let me know if you have noticed something wrong.