即使我正在工作,会话生命周期,Ajax和Symfony2,会话也会过期

时间:2015-01-30 15:48:26

标签: php ajax symfony session

如果用户在10分钟内没有做任何事情,我已将我的应用程序配置为超时关闭会话。在config.yml我有这个:

session:
    handler_id:  ~
    cookie_lifetime: 600 # 10 minutes
    gc_maxlifetime: 600 # 10 minutes
    gc_probability: 1
    gc_divisor: 1

我每隔一分钟进行一次Ajax调用,以检查会话是否即将到期或不会过期,这是我检查的内容:

public function isLoggedInAction(Request $request)
{
    $response = array();
    $response['authenticated'] = FALSE;
    $status = 200;
    $securityContext = $this->container->get('security.context');
    if ($securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
        $response['authenticated'] = TRUE;
    }

    return new JsonResponse($response, $status ?: 200);
}

对于某些 unknow 原因不起作用,并且每隔10分钟会话都会关闭,无论我是在使用网页还是不在,为什么?我错过了什么?

修改1 尝试了新值,但仍无效:

session:
    handler_id:  ~
    cookie_lifetime: 1800
    gc_maxlifetime: 600
    gc_probability: 1
    gc_divisor: 100

当我在页面上工作,执行Ajax调用和其他一些任务时,会话已关闭,因此无效。 显然对我来说唯一的价值就是设置cookie_lifetime: 86400 #1 day这对我来说很疯狂!

编辑2 @acontell 建议修复虚拟机时间和日期之后我尝试使用这个新值(10分钟需要太长时间,所以我&#39 ; ve改为3):

session:
    handler_id:  ~
    cookie_lifetime: 1800
    gc_maxlifetime: 180 # session will expire after 3 minutes of inactivity
    gc_probability: 1
    gc_divisor: 100

我还通过启用ntpd服务修复了VM上的日期/时间,现在日期很好:

[root@webvm var]# date
 Sun Feb  1 18:35:17 VET 2015

但是5分钟后(函数调用执行了5次)会话仍然存在。这就是我从Javascript端调用函数isLoggedInAction()的方法:

$.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
    if( data.authenticated ){
        var timer = window.setInterval(function(){
            $.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
                if( !data.authenticated ){
                    window.clearInterval(timer);
                    $.growl({
                        message: 'La sesión ha expirado por inactividad, debe <a href=""><b>iniciar seción</b></a> nuevamente.'
                    }, {
                        type: "danger",
                        allow_dismiss: false,
                        timer: 10000,
                        animate: {
                            enter: 'animated fadeInDown',
                            exit: 'animated fadeOutUp'
                        },
                        onHide: function(){
                            location.reload();
                        }
                    });
                }
            }).fail(function(){});
        },60000);
    }
}).fail(function(){});

见下图:

enter image description here

测试3

说完所有工作正常后,我做了最新的确定性测试:打开应用程序并在整个晚上(几乎8小时)保持不动,并且意外地从未关闭会话。如下图所示,查看该页面有多少请求,并查看会话仍然存在,为什么?

enter image description here

每隔一段时间进行一次Ajax调用:10.5分钟

$.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
    if( data.authenticated ){
        var timer = window.setInterval(function(){
            $.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
                if( !data.authenticated ){
                    window.clearInterval(timer);
                    $.growl({
                        message: 'La sesión ha expirado por inactividad, debe <a href=""><b>iniciar seción</b></a> nuevamente.'
                    }, {
                        type: "danger",
                        allow_dismiss: false,
                        timer: 10000,
                        animate: {
                            enter: 'animated fadeInDown',
                            exit: 'animated fadeOutUp'
                        },
                        onHide: function(){
                            location.reload();
                        }
                    });
                }
            }).fail(function(){});
        }, 210000);
    }
}).fail(function(){});

设置说会话应该过期:10分钟。

session:
    handler_id:  ~
    cookie_lifetime: 630000
    gc_maxlifetime: 630000 # session will expire after 10 minutes of inactivity 
    gc_probability: 1
    gc_divisor: 100

服务器上的时间很好:

[root@webvm sencamer.dev]# date
Mon Feb  2 07:26:53 VET 2015

我还应该检查什么?

测试5

好的,我还在做测试,因为这不是一个好的行为。所以,这就是我为这次测试所做的事情:

  • 打开应用程序并开始处理
  • 在某个时刻停止工作并让应用程序进行Ajax调用以检查会话是否仍然存在。 (会议还活着见下图)
  • 在第一次通话后,我继续处理该应用程序,因为 image 2 显示但是意外会话结束,应用程序关闭。

为什么呢?是什么导致了这种行为?这是基于我的参数吗?

此图像显示对函数的第一次也是唯一的调用

enter image description here

通话结束后,我继续工作但会话已关闭

enter image description here

3 个答案:

答案 0 :(得分:1)

首先,请注意您的gc_probabilitygc_divisor。如果两者都设置为1,则意味着每次会话初始化时启动垃圾收集器(GC)进程的概率为gc_probability / gc_divisor = 1/1 = 1(100%)。

您可以将其保留为默认值或为其提供更高的数字,以减少调用GC的可能性。

例如:

session:
        # handler_id set to null will use default session handler from php.ini
        handler_id:  ~
        cookie_lifetime: 600 # Ten minutes
        gc_probability: 1
        gc_divisor: 10000

此外,如果您正在使用虚拟机,请检查服务器的日期,生成的会话cookie将标记为time() + cookie_lifetime的到期时间,其中时间取自服务器。< / p>

如果服务器的日期不好,cookie可能会暂时到期。想象一下:服务器日期2015-01-31,您的浏览器2015-02-01。服务器在晚上11点发送在2015-01-31到期的cookie,您的浏览器会收到一个已经过期的cookie。

答案 1 :(得分:0)

尝试使用以下参数:

gc_probability: 0
gc_divisor    : 1000

答案 2 :(得分:0)

我知道这个问题很旧,但是这是一个棘手的问题,它帮助我构建了一些东西,因此这里是如何在symfony 4+中构建它的问题

文档https://symfony.com/doc/current/components/http_foundation/session_configuration.html中对此进行了解释,但仍然很棘手,因此有一个示例配置

parameters.yaml

parameters:
    session_lifetime: 1800 # 30 minutes

framework.yaml

framework:
    session:
        handler_id: 'session.handler.native_file'
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
        use_cookies: true
        cookie_secure: auto
        cookie_samesite: lax
        cookie_lifetime: 0 # cookie is destroyed when the browser is close
        gc_divisor: 100
        gc_probability: 100 # garbage collector process on each request (100/100)
        gc_maxlifetime: '%session_lifetime%' # session is destroyed after lifetime of user idle

twig.yaml

twig:
     globals:
         session_lifetime: '%session_lifetime%' # so you can use the variable in any template

AbstractController

// extend this one in the controllers
class AbstractController extends SymfonyAbstractController
{
    /**
     * @Route("/is-logged-in", name="is_logged_in")
     */
    public function isLoggedIn(Security $security)
    {
        $response = ['authenticated' => false];
        if ($security->isGranted('IS_AUTHENTICATED_FULLY')) {
            $response['authenticated'] = true;
        }

        return new JsonResponse($response);
    }
}

app.js

checkLoggedIn = function (isLoggedInUrl, loginUrl, sessionLifeTime) {
    
    let timer = window.setInterval(function () {
            $.ajax({
                url: isLoggedInUrl,
                method: 'GET',
                success: function (data) {
                    if (data['authenticated'] === true) {
                        console.log('checkLoggedIn OK');
                    } else {
                        window.clearInterval(timer);
                        // you can use any message system you want here instead of Toasts
                        $(document).Toasts('create', {
                            title: 'Warning',
                            body: 'Session expired, <a href="' + loginUrl + '">please reconnect</a>',
                            class: 'bg-danger',
                        });
                    }
                }
            })
        },
        (sessionLifeTime + 60) * 1000 // the login check will be sent 60 sec after session supposed expiration
    );
}

your_base_template.html.twig

<script>
    checkLoggedIn("{{ path('is_logged_in') }}", "{{ path('security_login') }}", {{ session_lifetime }});
</script>