簡體   English   中英

使用特定於標簽的Cookie而不使用sessionStorage或任何HTML5功能

[英]Tab specific cookies without using sessionStorage or any HTML5 features

我感興趣的是讓用戶能夠在我的網絡應用程序上登錄並注銷多個用戶會話cookie。 目前,身份驗證是標准的,並且唯一標識符允許我在用戶訪問我們的站點時對其進行身份驗證,如果他們提供了cookie中可用的身份驗證令牌。 典型用例適用於如果用戶從一個選項卡注銷,它會將其從另一個選項卡中注銷。 現在,它要求用戶從兩個獨特的瀏覽器實例登錄,以便能夠登錄到兩個不同的帳戶。

是否有非HTML5方式(使用標准javascript cookie)具有特定於標簽的cookie標識符? 我假設沒有明確的方法來解決這個問題,這需要從后端進行某種黑客+合作。 如果有一個沒有使用HTML5的解決方案,那將是理想的。

你不能。

有辦法處理這種情況,但沒有一種是簡單的。

如果你願意,你必須告訴用戶這樣做: 如何極客

從文檔: 使用sessionStorage存儲的數據不會在瀏覽器選項卡中保留,即使兩個選項卡都包含來自同一域來源的網頁。 換句話說, sessionStorage數據不僅限於調用頁面的域和目錄,而且還包含頁面所在的瀏覽器選項卡。與會話cookie相對照,會話cookie將數據從選項卡保留到選項卡。

一段時間后我實現了類似的行為。 所以,我做的是這樣的:

  1. 為此,您需要在URL中攜帶sessionId或作為頁面內容的一部分。
  2. 加載登錄頁面時,刪除sessionId cookie。
  3. 提交登錄時,服務器會在URL中為您提供登錄頁面以及sessionId,或者作為html響應正文的一部分。
  4. 從現在開始,在每次服務器調用之前,將會話cookie設置為您在URL或頁面內容中具有的cookie。
  5. 因此,每個選項卡都會在任何服務器調用之前設置自己的cookie,這將使請求在服務器上與正確的會話着陸。

在此之前,只有您使用相對URL時,此解決方案才有效! (用於圖像,鏈接甚至Ajax調用)

像在任何普通場景中一樣使用會話進行一次小的更改。 您將通過每個會話ID識別一台機器(瀏覽器),而不是使用每個會話ID識別用戶。 因此,當請求到達服務器時,它會識別在該計算機上使用您的網站的一群用戶。 每個用戶都有自己的子標識符(可以是順序計數器或隨機數)。 簡單來說,您的會話數據(由Cookie中的會話ID標識)包含一個關聯數組。 該陣列的每個條目保存由子標識符標識的一個特定用戶的會話數據。 例如,在PHP中,如果您的用戶的子標識符是user0 ,那么您可以訪問此用戶的會話數據,如:

<?php
session_start();
$user_data = $_SESSION['user0'];

接下來是如何傳遞用戶的子標識符。

您可以使用webserver的URL重寫。 您需要提出一個可以被視為普通文件夾名稱的模式,而沒有像這樣的文件夾。 例如:

RewriteEngine On
RewriteRule ^user(\d+)\/(.*)$ $2?sub_id=$1 [QSA,L]

在此示例中,您不允許使用user0user1等任何文件夾。如果某些請求要求http://domain.com/user0/index.php ,則會將其重寫為http://domain.com/index.php?sub_id=user0 現在在index.php你將擁有:

<?php
session_start();
$user_data = $_SESSION[$_REQUEST['sub_id']];

從這一點開始你應該使用$user_data而不是$_SESSION 唯一剩下的就是如何第一次生成子標識符。 這相對容易,您可以:

<?php
session_start();
if (!isset($_REQUEST['sub_id'])) {
    $sub_id = 0;
    while (isset($_SESSION["user{$sub_id}"])) {
        $sub_id++;
    }
    $_SESSION["user{$sub_id}"] = array();
    header("Location: /user{$sub_id}".$_SERVER['REQUEST_URI']);
    die();
}
else {
    $user_data = $_SESSION[$_REQUEST['sub_id']];
}

最后,只有當您的所有網址都是相對的時,一切都會有效! 不以/user0/開頭的每個絕對URL將被視為新用戶,並將導致會話中的新條目。

這種方法的好處是,只要URL已經相對解決,您當前的代碼將以最小的努力工作。

這是一個簡單的示例,說明如何創建用戶可以登錄多個帳戶的系統。 這不是安全檢查,必須添加。 這段代碼可以更好地編寫和優化。

inc.php

https://github.com/maksa9/multiple-user-login/blob/master/inc.php

此文件包含在每個php腳本中。

此部分檢查記錄了哪個用戶以及哪個帳戶處於活動狀態。 以下是根據活動帳戶創建php腳本的正確路徑的函數

// check which user is logged and which account is active
if(isset($_GET['user'])) $id_user = (int)$_GET['user'];
if($id_user > 0)
{
    if(isset($_SESSION['user'][$id_user]))
    {        
        $user_name = $_SESSION['user'][$id_user]['name'];
        $user_email = $_SESSION['user'][$id_user]['email'];                
    }
    else
        gotToLoginForm();
}

// If the user id is not specified and there is a user session, finds another id
if($id_user == 0 and isset($_SESSION['user']))
{    
    $sess = $_SESSION['user'];

    $id_user = (int)key($sess);

    if(isset($_SESSION['user'][$id_user]))
    {        
        $user_name = $_SESSION['user'][$id_user]['name'];
        $user_email = $_SESSION['user'][$id_user]['email'];  

        define('ID_USER',$id_user);

        gotToIndex();              
    }
    else
        gotToLoginForm();

}

define('ID_USER',$id_user);

loginform.php

https://github.com/maksa9/multiple-user-login/blob/master/loginform.php

使用post方法登錄的簡單表單。

的login.php

https://github.com/maksa9/multiple-user-login/blob/master/login.php

登錄用戶。 模擬對數據庫的查詢。

if(isset($_POST['email']))
    if(isset($_POST['pass']))
    {
        $email = $_POST['email'];
        $pass = $_POST['pass'];

        $id_user = 0;

        // simulates a query to the database
        if($email === 'test1@test.com' and $pass === '111')
        {
            $id_user = 1;
            $name='John Doe';
        }
        if($email === 'test2@test.com' and $pass === '222')
        {
            $id_user = 2;
            $name = 'Doe John';
        }

        // login user
        if($id_user > 0)
        {
            // checks if the user is already logged
            if( !isset($_SESSION['user'][$id_user]))
            {
                $_SESSION['user'][$id_user] = array('email'=>$email, 'name'=>$name);
            }

            //go to main page 
            $page = ROOT.'user/'.$id_user.'/index.php';            
            header('Location: '.$page);
            exit;

        }        
    }

的index.php

https://github.com/maksa9/multiple-user-login/blob/master/index.php

應用程序的主頁面。

<div>
    <h1>Welcome: <?php echo $user_name ?> (<?php echo $user_email ?>) [<?php echo $id_user ?>]</h1>


    <p><a href="<?php echo returnUrl('swap.php',$id_user)  ?>">Choose an account</a></p>    
    <p><a href="<?php echo returnUrl('loginform.php',$id_user)  ?>">Login with the another account</a></p>        
    <p><a href="<?php echo returnUrl('logout.php',$id_user)  ?>">Log out</a></p>

</div>

swap.php

https://github.com/maksa9/multiple-user-login/blob/master/swap.php

允許用戶選擇帳戶。

foreach($_SESSION['user'] as $idus => $userA)
{
    echo '<p><a href="'.returnUrl('index.php',$idus).'">'.$userA['name'].' ('.$userA['email'].') ['.$idus.']</a></p>';
}

logout.php

https://github.com/maksa9/multiple-user-login/blob/master/logout.php

注銷用戶。 檢查活動用戶帳戶並重定向(如果有)。

unset($_SESSION['user'][ID_USER]);

if(count($_SESSION['user']) == 0) 
    unset($_SESSION['user']);


// checks for active user accounts and redirects them if any
if(isset($_SESSION['user']))
{        
    $sess = $_SESSION['user'];

    $id_user = (int)key($sess);

    if(isset($_SESSION['user'][$id_user]))
    {            
        $page = ROOT.'user/'.$id_user.'/index.php';            
        header('Location: '.$page);
        exit;               
    }        
}    

的.htaccess

https://github.com/maksa9/multiple-user-login/blob/master/.htaccess

Options +FollowSymlinks
RewriteEngine On

RewriteRule ^user\/([0-9]*)\/index.php$ index.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/logout.php$ logout.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/login.php$ login.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/loginform.php$ loginform.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/swap.php$ swap.php?user=$1 [NC,L]

RewriteRule ^user\/$ index.php [NC,L]
RewriteRule ^user$ index.php [NC,L]

你不能

創建cookie時,可以通過設置其“根域”來控制其可見性。 然后,屬於該根的任何URL都可以訪問它。 例如,root可以設置為“example.com”,然后cookie將可用於“www.example.com”或“xyz.example.com”或“example.com”中的站點。 這可能用於允許相關頁面相互“通信”。 無法將根域設置為“頂級”域,例如“.com”或“.co.uk”,因為這樣可以廣泛訪問cookie。

默認情況下,cookie對其域中的所有路徑都是可見的,但在創建時,它們可以被限制到給定的子路徑 - 例如“www.example.com/images”。

所以任何具有相同根域的選項卡都可以訪問該cookie。

會話cookie是服務器特定的AFAIK,因此您可以為同一服務器設置不同的DNS名稱,例如子域名,如:session1.myserver.com,session2.myserver.com,session3.myserver.com

那么@ dm4web的回答是正確的,但你必須留意他的安全警告。 您可以做的最好的事情是采取雙向方法。

方向一

Regular Login.
Create a Unique session ID and pass it via the URL.

方向二

Check Session via i) Logged In User and ii) Check Session ID via URL Param

現在,我們來舉個例子:

$usrname: Fool
$psswd: dm4web

PHP代碼

session_start();
//all inputs should be sanitized
$sql = "SELECT * FROM `users` WHERE `usrname`='".$usrname."' AND `psswd` = '".$psswd."'":
$dbh = new PDO('odbc:db', 'db2inst1', 'ibmdb2');
$count = $dbh->exec($sql);
if($count > 0){
 //Guy is logged in
 $a = session_id();
 //**Use this $a in every URL parameter under current session**
}
else {
 //Go f**k yourself >> to the user ;)
}

但是你應該注意到你不能直接跳轉到那個用戶/傳遞匹配方案。 首先,您必須確保了解用戶是否已登錄。 此外,基於PHP的SESSION Cookie,你可以理解這一點

  1. 如果計算機上有活動登錄
  2. 如果URL上有活動登錄[從session_id事件中獲取$ a]

您在所有情況下都匹配 URL參數,與SESSION cookie交叉引用並繼續!

祝好運! 如果您還有其他問題,請與我們聯系!

暫無
暫無

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

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