javascript 不使用 sessionStorage 或任何 HTML5 功能的标签特定 cookie

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27137562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 07:00:47  来源:igfitidea点击:

Tab specific cookies without using sessionStorage or any HTML5 features

javascriptphpcookies

提问by randombits

I am interested in having users be able to login and logout with multiple user session cookies on my web app. Currently, authentication is done standard and a unique identifier allows me to authenticate a user when they visit our site back if they present an auth token that's available in their cookie. Typical use cases apply in that if the user logs out from one tab, it logs them out of another tab. Right now it requires having the user login from two unique browser instances in order to be able to login to two different accounts.

我有兴趣让用户能够在我的 Web 应用程序上使用多个用户会话 cookie 登录和注销。目前,身份验证已完成标准,如果用户提供 cookie 中可用的身份验证令牌,则唯一标识符允许我在用户访问我们的网站时对其进行身份验证。典型的用例适用于如果用户从一个选项卡注销,则会将他们从另一个选项卡注销。现在,它需要用户从两个唯一的浏览器实例登录,以便能够登录到两个不同的帐户。

Is there a non-HTML5 way (using standard javascript cookies) to have tab-specific cookie identifiers? I'm assuming that there is no clear cut way of going about this and it would require some kind of hack + cooperation from the backend. If there is a solution that makes sense without using HTML5, that would be ideal.

是否有非 HTML5 方式(使用标准 javascript cookie)来拥有特定于标签的 cookie 标识符?我假设没有明确的方法来解决这个问题,这需要后端的某种黑客+合作。如果有一个不使用 HTML5 就有意义的解决方案,那将是理想的。

回答by Prateek

You can't.

你不能。

There are ways to deal with this condition, but none of them are simple.

有多种方法可以处理这种情况,但都不是简单的方法。

If you want, you have to tell user to do like this: How to geek

如果你愿意,你必须告诉用户这样做:How to geek

From docs:Data stored using sessionStoragedo not persist across browser tabs, even if two tabs both contain webpages from the same domain origin. In other words, data inside sessionStorageis confined to not just the domain and directory of the invoking page, but the browser tab in which the page is contained in. Contrast that to session cookies, which do persist data from tab to tab.

来自文档:使用存储的数据sessionStorage不会跨浏览器选项卡持续存在,即使两个选项卡都包含来自同一域来源的网页。换句话说,内部数据sessionStorage不仅限于调用页面的域和目录,还包括页面所在的浏览器选项卡。与会话 cookie 形成对比,会话 cookie 确实在选项卡之间保留数据。

回答by thunder

I achieved similar behavior some time back. So, what I do is something like this:

前段时间我实现了类似的行为。所以,我所做的是这样的:

  1. For this to work, you need to carry the sessionId in the url or as part of the page content.
  2. When login page is loaded, delete the sessionId cookie.
  3. When login for is submitted, server gives you login page along with sessionId in the url or as part of html response body.
  4. From now onwards, before every server call, set the session cookie to the one that you have in the url or page content.
  5. So, each tab will set its own cookie before any server call which would make the request land with the right session on the server.
  1. 为此,您需要在 url 中或作为页面内容的一部分携带 sessionId。
  2. 加载登录页面后,删除 sessionId cookie。
  3. 提交登录后,服务器会在 url 中或作为 html 响应正文的一部分为您提供登录页面以及 sessionId。
  4. 从现在开始,在每次服务器调用之前,将会话 cookie 设置为您在 url 或页面内容中拥有的 cookie。
  5. 因此,每个选项卡将在任何服务器调用之前设置自己的 cookie,这将使请求以正确的会话登陆服务器。

回答by Mehran

Before anything, this solution works if you use relative URLs only! (for images, links and even Ajax calls)

首先,如果您仅使用相对 URL,则此解决方案有效!(用于图像、链接甚至 Ajax 调用)

Use sessions as you would in any ordinary scenario with one small change. Instead of identifying users with each session ID, you will identify a machine (a browser) by each session ID. So when requests arrive at server, it identifies a bunch of users who are using your website on that computer. Each user will have his own sub-identifier (it could be a sequential counter or a random number). Putting it simple, your session data (identified by session ID in the cookies) holds an associative array. Each entry of this array holds session data for one particular user identified by sub-identifier. For instance, in PHP, if your user's sub-identifier is user0, then you can access this user's session data like:

像在任何普通场景中一样使用会话,只需稍作改动。您将通过每个会话 ID 识别一台机器(浏览器),而不是使用每个会话 ID 来识别用户。因此,当请求到达服务器时,它会识别出在该计算机上使用您网站的一群用户。每个用户都有自己的子标识符(可以是顺序计数器或随机数)。简单来说,您的会话数据(由 cookie 中的会话 ID 标识)包含一个关联数组。此数组的每个条目保存由子标识符标识的一个特定用户的会话数据。例如,在 PHP 中,如果您的用户的子标识符是user0,那么您可以访问该用户的会话数据,例如:

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

Next is how to pass on user's sub-identifier.

接下来是如何传递用户的子标识符。

You can use webserver's URL rewrite. You need to come up with a pattern which can be considered as an ordinary folder name, while there's no folder named like that. For instance:

您可以使用网络服务器的 URL 重写。你需要想出一个模式,它可以被认为是一个普通的文件夹名称,而没有这样命名的文件夹。例如:

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

In this example, you are not allowed to have any folders like user0, user1etc. If some request asks for http://domain.com/user0/index.phpit will be rewritten to http://domain.com/index.php?sub_id=user0. Now in index.phpyou'll have:

在这个例子中,你不允许有任何文件夹,比如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']];

And you should use $user_datainstead of $_SESSIONfrom this point forth. The only thing that remains is how to generate sub-identifier for the first time. That's relatively easy, you can:

你应该使用$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']];
}

At the end, everything will work only if all your URLs are relative! Each absolute URL which does not start with /user0/will be considered a new user and will lead to a new entry in the session.

最后,只有当您的所有 URL 都是相对的时,一切才能正常工作!每个不以 开头的绝对 URL/user0/将被视为一个新用户,并将导致会话中的新条目。

The benefit of this approach is that your current code will work with minimum effort, as long as URLs are already addressed relatively.

这种方法的好处是,只要 URL 已经相对寻址,您当前的代码就可以以最少的工作量工作。

回答by dm4web

This is a simple example of how you can create a system in which a user can log in to multiple accounts. This is no safety checks and must be added. This code can be much better to write and optimize.

这是一个简单的示例,说明如何创建一个用户可以登录多个帐户的系统。这不是安全检查,必须添加。这段代码可以更好地编写和优化。

inc.php

inc.php

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

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

This file is included into each php script.

该文件包含在每个 php 脚本中。

This part check which user is logged and which account is active. Here are functions that create the proper path to the php scripts according to the active account

这部分检查哪个用户已登录以及哪个帐户处于活动状态。以下是根据活动帐户创建 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

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

Simple form to login with post method.

使用 post 方法登录的简单表单。

login.php

登录.php

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

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

Login user. simulates a query to the database.

登录用户。模拟对数据库的查询。

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 === '[email protected]' and $pass === '111')
        {
            $id_user = 1;
            $name='John Doe';
        }
        if($email === '[email protected]' 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

索引.php

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

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

Main page of the application.

应用程序的主页。

<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

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

Allows the user to choose the account.

允许用户选择帐户。

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

logout.php

登出.php

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

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

Logout user. Check for active user accounts and redirects them if any.

注销用户。检查活动用户帐户并重定向它们(如果有)。

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

.htaccess

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

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

Options +FollowSymlinks
RewriteEngine On

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

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

回答by Laxmikant Dange

You cant

你不能

When a cookie is created it is possible to control its visibility by setting its 'root domain'. It will then be accessible to any URL belonging to that root. For example the root could be set to "example.com" and the cookie would then be available to sites in "www.example.com" or "xyz.example.com" or "example.com". This might be used to allow related pages to 'communicate' with each other. It is not possible to set the root domain to 'top level' domains such as '.com' or '.co.uk' since this would allow widespread access to the cookie.

创建 cookie 时,可以通过设置其“根域”来控制其可见性。然后它可以被属于该根的任何 URL 访问。例如,可以将根设置为“example.com”,然后该 cookie 将可用于“www.example.com”或“xyz.example.com”或“example.com”中的站点。这可能用于允许相关页面相互“通信”。无法将根域设置为“顶级”域,例如“.com”或“.co.uk”,因为这将允许广泛访问 cookie。

By default cookies are visible to all paths in their domains, but at the time of creation they can be retricted to a given subpath - for example "www.example.com/images".

默认情况下,cookie 对其域中的所有路径都是可见的,但在创建时,它们可以被限制到给定的子路径 - 例如“www.example.com/images”。

so any tab which is having same root domain can access that cookie.

所以任何具有相同根域的选项卡都可以访问该 cookie。

回答by Chris

The session cookies are server specific AFAIK, so what you could do is set up different DNS names for the same server, e.g. subdomains like: session1.myserver.com, session2.myserver.com, session3.myserver.com

会话 cookie 是特定于服务器的 AFAIK,因此您可以为同一服务器设置不同的 DNS 名称,例如子域,如:session1.myserver.com、session2.myserver.com、session3.myserver.com

回答by Christian M. Raymonds

Well @dm4web's answer is kind of correct but you have to pay heedto his security warnings though. The best thing that you can do is take a bi-directional approach.

好吧@dm4web 的答案是正确的,但您必须注意他的安全警告。您能做的最好的事情是采用双向方法。

Direction One

方向一

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

Direction Two

方向二

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

Now, let's take an example:

现在,让我们举个例子:

$usrname: Fool
$psswd: dm4web

PHP Code

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

But you should notice that you can't directly jump into that user/pass match scheme. First you have to ensure that you find out if the user is already logged in or not. Also, based on the SESSION Cookie from PHP, you figure out that

但是你应该注意到你不能直接跳到那个用户/通行证匹配方案。首先,您必须确保确定用户是否已经登录。此外,根据 PHP 的 SESSION Cookie,您会发现

  1. If there is an active log in on the machine
  2. If there is an active login on the URL [vide the $a from the session_id thing]
  1. 如果机器上有活动登录
  2. 如果 URL 上有活动登录 [从 session_id 中获取 $a]

You matchthe URL parameter under all circumstances, cross reference with the SESSION cookie and proceed!

您在所有情况下都匹配URL 参数,与 SESSION cookie 交叉引用并继续!

Good Luck! Let me know if you've any more questions!

祝你好运!如果您还有其他问题,请告诉我!