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

Posted

技术标签:

【中文标题】即使我正在工作,会话也会过期,会话生命周期,Ajax 和 Symfony2【英文标题】:Session expires even if I'm working, session lifetime, Ajax and Symfony2 【发布时间】:2015-03-30 03:31:21 【问题描述】:

如果用户在 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);

由于某些未知原因无法正常工作,并且无论我是否正在使用页面,每 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 建议修复 VM 时间和日期后,我正在尝试使用这个新值(10 分钟太长,所以我改为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());

见下图:

测试 3

在说一切正常之后,我做了最新的和明确的测试:打开应用程序并在整个晚上(近 8 小时)保持不变,并惊讶它从未关闭会话。如下图所示,看看页面做了多少请求,看看会话如何仍然存在,为什么?

每 10.5 分钟进行一次 Ajax 调用

$.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 调用以检查会话是否仍然存在。 (会话仍然存在,见下图) 第一次通话后,我继续处理应用程序,如 图 2 所示,但意外会话结束并且应用程序关闭。

为什么?是什么导致了这种行为?根据我的参数是正确的吗?

这张图片显示了对函数的第一次也是唯一一次调用

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

【问题讨论】:

您是否在 php 脚本的顶部添加了 session_start() ?更新 yml 文件后,您是否重新启动了 Apache 服务器? @HalayemAnis session_start()?在这里适用吗?我不这么认为,因为 Symfony 做了这项工作,也许我弄错了,但我现在理解的是 注意你的 gc_probability 和 gc_divisor。你有两个,这意味着垃圾收集器(GC)进程在每次会话初始化时启动的概率是 gc_probability / gc_divisor = 1/1 = 1。 @acontell 我没关注你,有什么问题? @ReynierPM ,愚蠢的,愚蠢的我。 ... :^ ) 但我找到了解决方案。这很容易。不要指定cookie_lifetime。第一次访问后,您得到的 cookie 过期时间不再更新。 【参考方案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,该时间来自服务器。

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

【讨论】:

仍然无法正常工作,我已经更改了值,清除了缓存,但 PHP 方面仍然说 Ajax 上的 authenticated 已经进行了五次调用。这里最糟糕的部分是,有时我只是在工作并且会话刚刚到期,这正在扼杀我的大脑,因为我找不到问题所在。有没有机会比较 cookie 和 PHP 会话之间的值?提供更好线索的东西? 你确定你改了cookie_lifetime?在您的帖子中,您有变量gc_maxlifetime = 180 和cookie_lifetime = 1800。理论上,它应该可以工作。如果在 3 分钟内没有从该会话发出请求,则该会话应该过期。 是的,值是cookie_lifetime: 180 gc_maxlifetime: 180,除了 Ajax 请求检查会话是否仍然存在之外,没有发出任何请求 您多久发出一次 AJAX 请求?我的意思是,你必须发出一个 AJAX 请求,等待 3 分钟(比如说 3:30)然后再发出一个。如果您每分钟发出一个请求,则会话不会过期 嗯,这可能是问题所在,我唯一的疑问是如何在3:30 分钟拨打下一个电话?【参考方案2】:

试试这些参数:

gc_probability: 0
gc_divisor    : 1000

【讨论】:

【参考方案3】:

我知道这个问题很老,但这是一个棘手的问题,它帮助我构建了一些东西,所以这里是你如何在 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>

【讨论】:

以上是关于即使我正在工作,会话也会过期,会话生命周期,Ajax 和 Symfony2的主要内容,如果未能解决你的问题,请参考以下文章

即使会话过期,Laravel API 调用也会继续

如何在 Symfony 中延长会话 cookie 的生命周期?

Laravel 5 - 用户在会话生命周期后不注销

了解 ASP.Net 会话生命周期

PHP会话控制之失效时间与过期回收机制

cookie