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
Tab specific cookies without using sessionStorage or any HTML5 features
提问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
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 sessionStorage
do not persist across browser tabs, even if two tabs both contain webpages from the same domain origin. 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
不会跨浏览器选项卡持续存在,即使两个选项卡都包含来自同一域来源的网页。换句话说,内部数据sessionStorage
不仅限于调用页面的域和目录,还包括页面所在的浏览器选项卡。与会话 cookie 形成对比,会话 cookie 确实在选项卡之间保留数据。
回答by thunder
I achieved similar behavior some time back. So, what I do is something like this:
前段时间我实现了类似的行为。所以,我所做的是这样的:
- For this to work, you need to carry the sessionId in the url or as part of the page content.
- When login page is loaded, delete the sessionId cookie.
- When login for is submitted, server gives you login page along with sessionId in the url or as part of html response body.
- From now onwards, before every server call, set the session cookie to the one that you have in the url or page content.
- 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.
- 为此,您需要在 url 中或作为页面内容的一部分携带 sessionId。
- 加载登录页面后,删除 sessionId cookie。
- 提交登录后,服务器会在 url 中或作为 html 响应正文的一部分为您提供登录页面以及 sessionId。
- 从现在开始,在每次服务器调用之前,将会话 cookie 设置为您在 url 或页面内容中拥有的 cookie。
- 因此,每个选项卡将在任何服务器调用之前设置自己的 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
, 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
. Now in index.php
you'll have:
在这个例子中,你不允许有任何文件夹,比如user0
,user1
等等。如果某些请求要求,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_data
instead of $_SESSION
from 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,您会发现
- If there is an active log in on the machine
- If there is an active login on the URL [vide the $a from the session_id thing]
- 如果机器上有活动登录
- 如果 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!
祝你好运!如果您还有其他问题,请告诉我!