Automagically logout user after session expires

4.7k views Asked by At

I came across a problem: to logout a user automagically when the session is expired. I am trying to mimic the behavior in SugarCRM where once your session is expired, an alert tells you you've been logged out and you are redirecrec to the login screen to re-login. This happens with or without user interaction.

So far, in , the user has to perform a request beforehand. The session may have expired but the page is maintained until the user tries to perform a new request. While processing this request, the application can then check using controller filters, or a beforeAction() hook.

I would like to redirect them to the login page as soon as their session expires. How do I do this automagically?

5

There are 5 answers

0
Mihai P. On BEST ANSWER

All of the answers above are valid except... you have to implement the session in another way.

Any call to the server will basically reset your normal session. By checking every x seconds that you are still logged in you will make it so you are never logged out. On every check call your session expiry time will reset.

So this has to be combined with the fact that you will modify how the session is handled. You want on an actual page navigation to reset the session timer, not like PHP handles it by default.

0
vitr On

SugarCRM must check the session periodically with some javascript(ajax request), check the XHR on the Network tab in DevTool in Chrome, you will see this call right before the log out alert.

0
Jonathan Tweedy On

Here's a really simplistic example of how you might use JavaScript to make periodic ajax calls to check if the user is still logged in. This presumes that your backend PHP script returns a particular format of {"loggedin":true/false} and that your ajax() function takes three parameters that I'm actually using below, so you'll have to modify the syntax to make this suit your needs and accommodate the requirements of whatever ajax function you actually use (like in jQuery, native JS, whatever you use)...

var checkLogin = function() {
    //// presumes that you have some ajax function going
    //// with something like ajax(method,url,callback)
    //// and that it's returning something like {loggedin:true/false}
    ajax("GET", "some-check-login-script.php", function(json) {
        var data = JSON.parse(json);
        if (!data.loggedin) {
            runSomeFunctionToAlertOrRefreshOrWhatever();
            clearInterval(logincheckinterval);
        }
    });
}
var logincheckinterval = setInterval(checkLogin, 5000);

You'll just need to modify the syntax to match your particular framework's requirements for making that ajax call, and then modify the rest accordingly to do whatever you want it to do (alert, prompt, custom dialog, whatever) once it catches a 'false' value back from the data returned.

Hope that's helpful.

0
Pavel Bariev On

I had the same task on my Yii2 app before and this is what I did.

  1. Created widget with js setInterval and inserted it in main layout.

    class UserTimeout extends Widget
    {
        public $checkUrl = ['/index/check-user-timeout'];
        public $redirectUrl = ['/index/login'];
    
    
    public function run()
    {
        $timeout = \Yii::$app->user->authTimeout * 1000 + 5000; // milliseconds
        $url = Url::to($this->checkUrl);
        $redirect = Url::to($this->redirectUrl);
        $this->view->registerJs("
            function checkUserTimeout() {
                $.post('{$url}', function(data){
                    if(data){
                        document.location = '{$redirect}';
                    }
                });
            }
            setInterval(checkUserTimeout, $timeout);
        ");
    }
    
    }
  2. Turned off autoLogin in user component:

    'components'          => [
        'user'         => [
            'enableAutoLogin' => false,
            'authTimeout'     => 60 * 60,
    

Frankly speaking I made it with event yii\web\Application 'beforeRequest' because I needed autologin by cookie to be enabled for other requests.

  1. Made 'index/check-user-timeout' action:

    public function actionUserTimeout()
    {
            $expire = time() - Yii::$app->session->get('__expire');
            if ($expire >= 0) {
                Yii::$app->session->setFlash('warning', Yii::t('common', 'auth_timeout'));
                return true;
            }
            return false;
    }
    

    It's important to avoid checking user identity before this action (do not do something like this in it's beforeAction() or related events: "if (Yii::$app->user->isGuest)") - this will refresh session expire value.

0
pappfer On

User component should look something like this:

'user' => [
    'identityClass' => 'app\models\User',
    'authTimeout' => 300, 
    'enableAutoLogin' => false, // !important to set this
],

If you also want to set authTimeout on the fly

I came across the same issue. I wanted to set the user's authTimeout on the fly and I also wanted the user to be automatically logged out and redirected to the login screen after the time expires (no matter whether there was a user interaction or not). This is how I did it. I've set the user authTimeout and the session timeout to the same value in config/web.php and I also registered a new meta tag which will refresh the page 5 seconds after the session expires, so it will automatically redirect to the login screen.

In config/web.php:

'on beforeRequest' => function ($event) {
    $user = Yii::$app->user;

    if (!$user->isGuest) {
        if (!empty(Yii::$app->params['settings']['security_timeout'])) {
            $user->authTimeout = intval(Yii::$app->params['settings']['security_timeout']);
            Yii::$app->session->set($user->authTimeoutParam, time() + $user->authTimeout);
            Yii::$app->view->registerMetaTag(['http-equiv' => 'refresh', 'content' => $user->authTimeout + 5]);
        }
    }
},

Of course it is much simpler if you don't want to set the authTimeout on the fly.

If you don't need to set authTimeout on the fly

Just register the meta tag in your layout or anywhere in the product and set the refresh time a little higher than the authTimeout.

Yii::$app->view->registerMetaTag(['http-equiv' => 'refresh', 'content' => Yii::$app->user->authTimeout + 5]);