Javascript 如何停止AJAX调用以使PHP会话保持活动状态

Javascript 如何停止AJAX调用以使PHP会话保持活动状态,javascript,ajax,cakephp,php,Javascript,Ajax,Cakephp,Php,我的网站上有一个使用CakePHP的身份验证系统。它为此使用PHP会话 我现在使用的是一个AJAX调用(在每分钟运行一次的setInterval内),该调用检查用户是否仍然登录。如果返回false,则Javascript将获取当前URL并尝试重定向它们,从而将它们重定向到登录页面。理论上,这是有效的,因为它主动要求用户重新登录,而不是举行一个过时的会话,该会话只要求用户在单击某个内容时立即登录。我的问题是,我的AJAX调用使会话保持活动状态。所以永远不要注销(这是我们不想要的) 在CakePHP

我的网站上有一个使用CakePHP的身份验证系统。它为此使用PHP会话

我现在使用的是一个AJAX调用(在每分钟运行一次的setInterval内),该调用检查用户是否仍然登录。如果返回false,则Javascript将获取当前URL并尝试重定向它们,从而将它们重定向到登录页面。理论上,这是有效的,因为它主动要求用户重新登录,而不是举行一个过时的会话,该会话只要求用户在单击某个内容时立即登录。我的问题是,我的AJAX调用使会话保持活动状态。所以永远不要注销(这是我们不想要的)


在CakePHP或任何其他方法中,我能做些什么来阻止这种情况发生吗?

您描述的AJAX ping最常用于保持会话活动。您在会话处于活动状态时访问了应用程序这一事实本身就是在刷新它

您可以执行以下操作之一:

  • 进行固定时间的会议,例如30分钟,然后 总是过期(不确定这是否是个好主意)并保持ping
  • 更改逻辑,使您根本不必ping,并且在会话到期和用户 无论是导航到新页面还是执行AJAX会话,服务器都会返回相应的状态代码和/或将用户重定向到登录页面

我会选择第二个选项。

显而易见的方法是:

  • 不要在Ajax端点中调用session_start()
  • 使用后门实现您自己的会话处理程序,该后门允许您跳过写入部分(例如,基于全局变量或当前URL的状态)

  • 作为一个丑陋的黑客,您可以尝试调用session_id(“dummy”);或者在Ajax端点中调用session_start()后更改会话处理程序。

    正如我在评论中提到的,您可以创建一个包含以下内容的javascript文件,并在所有页面中调用该文件

    setTimeout("checkSession()",1800000);
    function checkSession(){
         //alert("Your session has expired due to inactivity. You will be logged out");
         window.location.reload();//or window.location="logoutAction";
    }
    

    我认为您不能仅依靠Auth会话来完成此任务

    我要做的是在用户表上创建一个新字段来跟踪上一个活动,类似于作为mysql时间戳的
    last_activity
    。然后在
    AppController::beforeFilter()
    中,将此字段设置为使用当前日期时间更新(因此每次请求都会发生),但如果是ping操作发出请求,则将其设置为跳过此字段(您可以选中
    $this->here
    或甚至为其他操作添加自己的参数)

    您的Ajax ping显然只是读取此字段,如果在几分钟前超过x个数量,您将注销该用户。

    在检查会话的有效性时,向查询字符串添加
    &Ajax=
    (任何内容)

    然后,更改PHP会话代码:

    session_start();
    if(!isset($_GET["ajax"])) $_SESSION["lastactivity"] = time();
    if(now() - $_SESSION["lastactivity"] > 3600){ //3600 seconds
        header("Location: login.php?url="+urlencode(str_replace("&ajax=", "", $_SERVER["REQUEST_URI"])));
        //Example:
        // Location: login.php?url=/sensible/secret.php?mode=show&hide=nothing
        exit;
    }
    

    这并不能完全回答您提出的问题,但我认为这是一个我想与大家分享的最佳实践

    setInterval()实际上并不像您期望的那样工作。这并不意味着您的代码将每分钟执行一次,它只确保您的代码将每分钟添加到队列中

    问题是计时器代码可能无法完成执行 在代码再次添加到队列之前。结果是 计时器代码连续运行多次,没有时间限制 在他们之间。幸运的是,JavaScript引擎足够聪明,可以 避免这个问题。使用setInterval()时,会将计时器代码添加到 仅当没有计时器代码的其他实例时才显示队列 已经在排队了。这确保了添加 队列的计时器代码至少为指定的间隔

    这种重复计时规则的缺点有两个:(1) 可以跳过间隔,(2)间隔可以小于 应在多个计时器代码执行之间。。。 -N.Zakas,面向Web开发人员的专业JavaScript

    解决方法是将计时器代码格式化如下:

    setTimeout( function() {
    
           // code to be run
    
           setTimeout( arguments.callee, *interval* );
    
    }, *interval* );
    

    注意:arguments.callee不能在严格模式下使用。

    在这里,我派生了一个用于检测会话是否处于活动状态的解决方案

    不需要任何间接费用。。 我们可以检测并重定向正常http请求的会话超时。 正如在ajax中一样,我们应该用一些逻辑来区别对待它

    #步骤1(在服务器端) 在php端。 首先创建一个身份验证函数,该函数必须在所有页面的第一行中调用此身份验证

    最好在config.php文件或auth.php文件中添加此auth()函数,并在创建会话后将其包含在所有php文件中

    包括'config/auth.php'

    // in auth.php file copy and past the following lines 
    
          function auth() {
            if (!isset($_SESSION['USER_ID'])) {
            //  checking whether the request is ajax or not. Ajax requests are xml http request 
                if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
                   // set a status code manually. 418 is unused http code
                    header("HTTP/1.0 418 Session Timeout", TRUE);
                   //  return or send a json response with status string and location to redirect
                    echo json_encode(array(
                        "status" => "time_out",
                        "location" => BASE_URL . "login.php?message=Session Timeout! Please log in and Try again.",
                    ));
                    exit;
                }
           // whether the request is normal http request do the redirection from the server side
                if (basename($_SERVER['PHP_SELF']) != 'login.php') {
                    header("Location:" . BASE_URL . "login.php");
                }
            } }
    
    #步骤2(在客户端) 这里我使用jQuery 创建一个js文件,该文件必须调用项目中的所有html(模板)页面

    最好包含在Commo页眉或页脚中

    创建一个ajax设置

    $.ajaxSetup({
        statusCode: {
            418: function (respose) {
                // $.parseJSON() can avoid by specifying dataType:"json" in ajax parameters
                var jsonObject = $.parseJSON(respose.responseText);
                if (jsonObject.status == "time_out") {
                    window.location = jsonObject.location;
                }
            }
        }
    });
    

    祝您愉快……

    我也在寻找解决这个问题的方法。我所做的是在页面加载后立即调用setTimeout(),等待会话时间,然后重定向到注销页面。我知道这不是一个好主意,这就是为什么我有兴趣在这里得到一个解决方案见我下面关于setInterval()行为的答案这两点都不符合OP的要求。如果用户离开系统很长一段时间,其他人看着屏幕怎么办。虽然他无法访问任何页面(执行任何服务器操作都将注销te会话),但他仍然可以看到页面上当前可用的信息。OP使用的轮询方法将在会话到期后立即从客户端注销会话如果这是OP的目的(我不理解,但可能是这样),然后我建议在一段时间不活动后(例如10分钟,页面上没有任何操作)进行固定会话和自动注销。我只在像我的网上银行这样的超级重要的网站上看到这种行为。如果这是我