簡體   English   中英

我怎樣才能停止 AJAX 呼叫保持 PHP Session 活着

[英]How can i stop an AJAX call keeping a PHP Session alive

我的站點上有一個使用 CakePHP 的身份驗證系統。 它為此使用 PHP 會話。

What i have in place is an AJAX call (within a setInterval running every minute) to a function which checks if the user is still logged in. If it returns false, then the Javascript takes the current URL and attempts to redirect them, which in turn 將他們重定向到登錄頁面。 從理論上講,這是可行的,因為它主動要求用戶重新登錄,而不是持有陳舊的 session,后者只會要求他們在單擊某些內容時立即登錄。 我的問題是我的 AJAX 調用使 session 保持活動狀態。 所以永遠不要退出(我們不想要)

我可以在 CakePHP 或任何其他我可以用來阻止這種情況發生的方法中做些什么嗎?

當您檢查 session 的有效性時,將&ajax= (anything) 添加到查詢字符串。

然后,更改您的 PHP session 代碼:

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 不能在嚴格模式下使用。

在這里,我推導出了一個用於檢測 session 是否存在的解決方案。

不需要任何開銷。我們可以在正常的 http 請求上檢測並重定向 session 超時。 就像在 ajax 中一樣,我們應該用一些邏輯來區別對待。

# 第 1 步(在服務器端)

在 php 端。 首先創建一個身份驗證 function 應該必須在所有頁面的第一行調用此身份驗證。

Best to add this auth() function in config.php file or auth.php file and include in all the php file after the session creation.

包括'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( 模板 ) 頁面中調用。

最好包含在commen header 或頁腳中

創建 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;
            }
        }
    }
});

祝你有美好的一天...

您描述的 AJAX ping 最常用於此目的 - 保持 session 活着。 您在 session 處於活動狀態時訪問了您的應用程序,這一事實正在刷新它。

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

  • 有一個固定長度的 session 例如 30 分鍾,之后它總是會過期(不確定這是否是個好主意)並保持 ping
  • 更改邏輯以使您根本不 ping,並且當 session 到期並且用戶導航到新頁面或執行 AJAX Z21D6F40CFB511982E4424E0E250A955 時,用戶將重定向到適當的頁面狀態代碼和/或返回服務器.

我會選擇第二個選項 go 。

這樣做的明顯方法是:

  1. 不要在 Ajax 端點中調用 session_start()
  2. 使用允許您跳過寫入部分的后門實現您自己的 session 處理程序(例如,基於全局變量的 state 或當前 URL)

作為一個丑陋的黑客,你可以嘗試調用 session_id('dummy'); 或在 Ajax 端點中調用 session_start() 后更改 session 處理程序。

正如我在評論中提到的,您可以創建一個包含以下內容的 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 session 來實現這一點。

我要做的是在用戶表上創建一個新字段來跟蹤上次活動,例如last_activity作為 mysql 時間戳。 然后在您的AppController::beforeFilter()中,將此字段設置為使用當前日期時間進行更新(因此每個請求都會發生),但如果是您發出請求的 ping 操作,則將其設置為跳過此字段(您可以檢查$this->here或者甚至為其他操作添加您自己的參數)。

您的 Ajax ping 顯然只是讀取此字段,如果超過 x 分鍾前,您將注銷用戶。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM