会话过期后自动注销用户

Automagically logout user after session expires

我遇到了一个问题:在会话过期时自动 注销用户。我正在尝试模仿 SugarCRM 中的行为,一旦您的会话过期,就会有一个警报告诉您您已经注销,并且您将重定向到登录屏幕以重新登录。 无论有没有用户交互都会发生这种情况。

到目前为止,在中,用户必须事先执行请求。会话可能已过期,但页面会一直保留到用户尝试执行新请求为止。在处理此请求时,应用程序可以使用控制器过滤器或 beforeAction() 挂钩进行检查。

我想在他们的会话过期后立即将他们重定向到登录页面。我如何自动执行此操作?

SugarCRM 必须通过某些 javascript(ajax 请求)定期检查会话,检查 Chrome 中 DevTool 中“网络”选项卡上的 XHR,您将在之前看到此调用注销警报。

这是一个非常简单的示例,说明您如何使用 JavaScript 定期调用 ajax 来检查用户是否仍处于登录状态。这假定您的后端 PHP 脚本returns {"loggedin":true/false} 的特定格式并且您的 ajax() 函数采用我在下面实际使用的三个参数,因此您必须修改语法以使其适合您的需要并适应您实际使用的任何 ajax 函数的要求(如 jQuery、原生 JS,无论您使用什么)...

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);

您只需要修改语法以满足特定框架对进行 ajax 调用的要求,然后相应地修改其余部分以执行您希望它执行的任何操作(警报、提示、自定义对话框,无论什么)一旦它从返回的数据中捕获到 'false' 值。

希望对您有所帮助。

以上所有答案均有效,除了...您必须以其他方式实现会话。

对服务器的任何调用基本上都会重置您的正常会话。通过每 x 秒检查一次您是否仍处于登录状态,您将做到这一点,因此您永远不会注销。在每次检查呼叫时,您的会话到期时间都会重置。

所以这必须与您将修改会话处理方式的事实相结合。您希望在实际页面导航上重置会话计时器,而不是像 PHP 默认处理它。

我之前在我的 Yii2 应用程序上有同样的任务,这就是我所做的。

  1. 使用 js setInterval 创建了小部件并将其插入到主布局中。

    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. 关闭了用户组件中的自动登录:

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

坦率地说,我是通过事件 yii\web\Application 'beforeRequest' 实现的,因为我需要通过 cookie 自动登录才能为其他请求启用。

  1. 进行了 'index/check-user-timeout' 操作:

    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;
    }
    

    重要的是避免在此操作之前检查用户身份(不要在它的 beforeAction() 或相关事件中执行类似的操作:"if (Yii::$app->user->isGuest)")- 这将刷新会话过期值。

用户组件应如下所示:

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

如果您还想即时设置authTimeout

我遇到了同样的问题。我想即时设置用户的 authTimeout,我还希望用户在时间到期后自动注销并重定向到登录屏幕(无论是否有用户交互)。我就是这样做的。我已经在 config/web.php 中将用户 authTimeout 和会话超时设置为相同的值,并且我还注册了一个新的元标记,它将在会话过期 5 秒后刷新页面,因此它会自动重定向到登录屏幕。

在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]);
        }
    }
},

当然,如果你不想即时设置 authTimeout 就简单多了。

如果不需要即时设置authTimeout

只需在您的布局或产品中的任何位置注册元标记,并将刷新时间设置为比 authTimeout 稍微长一点。

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