简体   繁体   English

使用特定于标签的Cookie而不使用sessionStorage或任何HTML5功能

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

I am interested in having users be able to login and logout with multiple user session cookies on my web app. 我感兴趣的是让用户能够在我的网络应用程序上登录并注销多个用户会话cookie。 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. 目前,身份验证是标准的,并且唯一标识符允许我在用户访问我们的站点时对其进行身份验证,如果他们提供了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. 现在,它要求用户从两个独特的浏览器实例登录,以便能够登录到两个不同的帐户。

Is there a non-HTML5 way (using standard javascript cookies) to have tab-specific cookie identifiers? 是否有非HTML5方式(使用标准javascript cookie)具有特定于标签的cookie标识符? 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的解决方案,那将是理想的。

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 如果你愿意,你必须告诉用户这样做: 如何极客

From docs: Data stored using sessionStorage do not persist across browser tabs, even if two tabs both contain webpages from the same domain origin. 从文档: 使用sessionStorage存储的数据不会在浏览器选项卡中保留,即使两个选项卡都包含来自同一域来源的网页。 In other words, data inside sessionStorage is 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数据不仅限于调用页面的域和目录,而且还包含页面所在的浏览器选项卡。与会话cookie相对照,会话cookie将数据从选项卡保留到选项卡。

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. 为此,您需要在URL中携带sessionId或作为页面内容的一部分。
  2. When login page is loaded, delete the sessionId cookie. 加载登录页面时,删除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. 提交登录时,服务器会在URL中为您提供登录页面以及sessionId,或者作为html响应正文的一部分。
  4. From now onwards, before every server call, set the session cookie to the one that you have in the url or page content. 从现在开始,在每次服务器调用之前,将会话cookie设置为您在URL或页面内容中具有的cookie。
  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. 因此,每个选项卡都会在任何服务器调用之前设置自己的cookie,这将使请求在服务器上与正确的会话着陆。

Before anything, this solution works if you use relative URLs only! 在此之前,只有您使用相对URL时,此解决方案才有效! (for images, links and even Ajax calls) (用于图像,链接甚至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. 您将通过每个会话ID识别一台机器(浏览器),而不是使用每个会话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. 简单来说,您的会话数据(由Cookie中的会话ID标识)包含一个关联数组。 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: 例如,在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. 您可以使用webserver的URL重写。 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: 例如:

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

In this example, you are not allowed to have any folders like user0 , user1 etc. If some request asks for http://domain.com/user0/index.php it will be rewritten to http://domain.com/index.php?sub_id=user0 . 在此示例中,您不允许使用user0user1等任何文件夹。如果某些请求要求http://domain.com/user0/index.php ,则会将其重写为http://domain.com/index.php?sub_id=user0 Now in index.php you'll have: 现在在index.php你将拥有:

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

And you should use $user_data instead of $_SESSION from this point forth. 从这一点开始你应该使用$user_data而不是$_SESSION The only thing that remains is how to generate sub-identifier for the first time. 唯一剩下的就是如何第一次生成子标识符。 That's relatively easy, you can: 这相对容易,您可以:

<?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. 不以/user0/开头的每个绝对URL将被视为新用户,并将导致会话中的新条目。

The benefit of this approach is that your current code will work with minimum effort, as long as URLs are already addressed relatively. 这种方法的好处是,只要URL已经相对解决,您当前的代码将以最小的努力工作。

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 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 的login.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 === '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 的index.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 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 logout.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=$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]

You cant 你不能

When a cookie is created it is possible to control its visibility by setting its 'root domain'. 创建cookie时,可以通过设置其“根域”来控制其可见性。 It will then be accessible to any URL belonging to that root. 然后,属于该根的任何URL都可以访问它。 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". 例如,root可以设置为“example.com”,然后cookie将可用于“www.example.com”或“xyz.example.com”或“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. 无法将根域设置为“顶级”域,例如“.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。

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

Well @dm4web's answer is kind of correct but you have to pay heed to his security warnings though. 那么@ dm4web的回答是正确的,但你必须留意他的安全警告。 The best thing that you can do is take a bi-directional approach. 您可以做的最好的事情是采取双向方法。

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] 如果URL上有活动登录[从session_id事件中获取$ a]

You match the 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! 如果您还有其他问题,请与我们联系!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM