如何区分浏览器标签中的会话?

在使用JSP和Servlets在java中实现的Web应用程序中; 如果我将信息存储在用户会话中,则将从同一浏览器的所有选项卡共享此信息。 如何区分浏览器选项卡中的会话? 在这个例子中:

<%@page language="java"%> <% String user = request.getParameter("user"); user = (user == null ? (String)session.getAttribute("SESSIONS_USER") : user); session.setAttribute("SESSIONS_USER",user); %> <html><head></head><body> <%=user %> <form method="post"> User:<input name="user" value=""> <input type="submit" value="send"> </form> </body></html> 

将这个代码复制到一个jsp页面( testpage.jsp )中,将这个文件部署在服务器上的一个Web应用程序的现有上下文中(我使用Apache Tomcat),然后使用正确的URL打开浏览器(FF,IE7或Opera) localhost/context1/testpage.jsp ),在input中input你的名字并提交表单。 然后在同一个浏览器中打开一个新的标签页,然后你可以在新标签页上看到你的名字(从会话中获得)。 浏览器caching要小心,有时似乎不会发生,但它在caching中,刷新第二个选项卡。

谢谢。

您可以使用HTML5 SessionStorage(window.sessionStorage)。 您将生成一个随机ID并保存在会话存储每浏览器选项卡中。 然后,每个浏览器选项卡都有自己的ID。

使用sessionStorage存储的数据不会跨浏览器选项卡保留,即使两个选项卡都包含来自相同域源的网页。 换句话说,sessionStorage中的数据不仅限于调用页面的域和目录,还包含页面所在的浏览器选项卡。与会话cookie相比,会话cookie会将数据从选项卡保存到选项卡。

你必须认识到,服务器端会话是HTTP的一个虚拟附件。 由于HTTP是无状态的,因此服务器需要以某种方式识别请求属于它所知道的特定用户并且具有会话。 有两种方法可以做到这一点:

  • cookies。 更清洁和更受欢迎的方法,但它意味着所有浏览器标签和窗口由一个用户共享会话 – IMO这实际上是可取的,我会非常恼火在一个网站,使我login每个新标签,因为我使用标签非常密集
  • URL重写。 网站上的任何url都附有一个会话ID。 这是更多的工作(你必须做任何事情,你有一个网站的内部链接),但可以在不同的标签单独的会话,虽然通过链接打开的标签仍然会共享会话。 这也意味着用户在进入您的网站时总是需要login。

你究竟想做什么? 你为什么要标签有单独的会议? 也许有一种方法可以实现你的目标而不使用会话呢?

编辑:为了testing,可以find其他解决scheme(例如在单独的虚拟机上运行多个浏览器实例)。 如果一个用户需要同时扮演不同的angular色,那么应该在应用中处理“angular色”概念,以便一个login可以有多个angular色。 您必须决定使用URL重写,还是仅仅使用当前情况,这是否可以接受,因为使用基于cookie的会话单独处理浏览器选项卡是不可能的。

window.name Javascript属性是唯一可以保持跨标签活动的东西,但是可以保持独立(而不是URL guff)。

你不应该。 如果你想做这样的事情,或者你需要强制用户使用一个实例的应用程序通过编写URLdynamic使用SessionID一样(不sessionid它不会工作)ID并传递它在每个URL。

我不知道为什么你需要它,但除非你需要做一个完全不可用的应用程序,不要这样做。

我想出了一个新的解决scheme,它有一点点的开销,但似乎只是一个原型。 一个假设是,你在一个荣誉系统的环境login,虽然这可以适应通过重新请求密码,每当你切换标签。

使用localStorage(或等效)和HTML5存储事件来检测新的浏览器选项卡何时切换哪个用户处于活动状态。 当发生这种情况时,创build一个带有消息的鬼覆盖图,说明你不能使用当前窗口(或者暂时禁用窗口,你可能不希望它是这个显眼的)。当窗口重新获得焦点时,发送一个AJAX请求logging用户回来了。

这种方法的一个警告:你不能有任何正常的AJAX调用(即依赖于你的会话的调用)发生在没有焦点的窗口中(例如,如果你有一个延迟发生的呼叫),除非您在此之前手动进行AJAX重新login呼叫。 所以你真正需要做的就是先检查你的AJAX函数,确保localStorage.currently_logged_in_user_id === window.yourAppNameSpace.user_id,如果没有,首先通过AJAXlogin。

另一个是竞争条件:如果你可以快速切换窗口来混淆它,你可能会得到一个relogin1-> relogin2-> ajax1-> ajax2序列,而ajax1是在错误的会话下产生的。 通过将loginAJAX请求推入数组,然后在存储上并在发出新的login请求之前解决所有当前请求。

最后一个要注意的是刷新窗口。 如果有人在您的AJAXlogin请求处于活动状态但尚未完成的情况下刷新窗口,则会以错误的人员名称刷新该窗口。 在这种情况下,您可以使用非标准的beforeunload事件来警告用户有关可能的混音,并要求他们单击取消,同时重新发布AJAXlogin请求。 然后他们可以把它弄糊涂的唯一方法是在请求完成之前点击确定(或者意外地敲击回车/空格键,因为OK是 – 不幸的是这种情况是默认的)。还有其他方法来处理这种情况,比如检测F5和Ctrl + R / Alt + R按键,这些按键在大多数情况下都能正常工作,但可能会受到用户键盘快捷键重新configuration或备用操作系统使用的阻碍。 但是,实际上这是一个边缘情况,最糟糕的情况从来就不是那么糟糕:在荣誉系统configuration中,您将以错误的人身份login(但您可以明显地看出这是通过个性化页面颜色,风格,显着名称等)。 在密码configuration中,负责input密码的最后一个人已经注销或分享了他们的会话,或者如果这个人实际上是当前用户,那么没有违反。

但是,最终你有一个单用户的标签应用程序(希望)只是应该这样做,而不必一定要设置configuration文件,使用IE或重写URL。 确保你在login到特定选项卡的每个选项卡中显而易见,但是…

我们有这个问题,我们很容易解决。 我的意思是容易,因为没有编程涉及 我们想要做的是让用户在同一浏览器窗口中login到多个帐户而不会冲突会话。

所以解决scheme是随机的子域名。

 23423.abc.com 242234.abc.com 235643.abc.com 

因此,我们要求我们的系统pipe理员为* .abc.comconfigurationSSL证书,而不是abc.com。然后,只需很less的代码更改,每次用户尝试login时,都会使用随机子域编号login到一个选项卡。 所以每个标签都可以独立拥有自己的会话。 同样为了避免任何冲突,我们使用用户ID的散列或md5开发了随机数。

我会在这里诚实。 。 。 上面的所有内容都可能是也可能不是真的,但是这似乎太复杂了,或者不知道服务器端使用哪个标签。

有时我们需要应用奥卡姆剃刀。

这里是奥卡姆的方法:(不,我不是奥卡姆,他死于1347年)

1)在加载页面时为浏览器分配一个唯一的ID。 。 。 当且仅当窗口还没有id(所以使用前缀和检测)

2)在每个页面上(使用全局文件或其他东西)只需将代码放在适当位置来检测焦点事件和/或鼠标hover事件。 (我会使用jquery这个部分,为了便于代码编写)

3)在你的焦点(和/或鼠标hover)function,设置一个cookie的window.name在其中

4)当您需要读取/写入选项卡特定数据时,从服务器端读取该cookie值。

客户端:

 //Events $(window).ready(function() {generateWindowID()}); $(window).focus(function() {setAppId()}); $(window).mouseover(function() {setAppId()}); function generateWindowID() { //first see if the name is already set, if not, set it. if (se_appframe().name.indexOf("SEAppId") == -1){ "window.name = 'SEAppId' + (new Date()).getTime() } setAppId() } function setAppId() { //generate the cookie strCookie = 'seAppId=' + se_appframe().name + ';'; strCookie += ' path=/'; if (window.location.protocol.toLowerCase() == 'https:'){ strCookie += ' secure;'; } document.cookie = strCookie; } 

服务器端(C# – 例如用途)

 //variable name string varname = ""; HttpCookie aCookie = Request.Cookies["seAppId"]; if(aCookie != null) { varname = Request.Cookies["seAppId"].Value + "_"; } varname += "_mySessionVariable"; //write session data Session[varname] = "ABC123"; //readsession data String myVariable = Session[varname]; 

完成。

我想你可能想要的是保持导航状态跨标签,而不是专门为每个标签创build一个会话。 这正是Seam框架通过对话范围/上下文实现的。 他们的实现依赖于每个请求传播一个对话id,并在服务器端创build对话的概念,这是介于会话和请求之间的事实。 它允许导航stream量控制和状态pipe理。

虽然这主要是针对JSF的,但请看一下,看看是否可以从中获得一些想法: http : //docs.jboss.org/seam/latest/reference/en-US/html_single/#d0e3620

在JavaScript中,我怎样才能唯一标识一个浏览器窗口从另一个在同一cookiedbased sessionId下

基本上使用window.name。 如果未设置,则将其设置为唯一值并使用它。 在属于同一会话的选项卡上,这将是不同的。

您可以使用链接重写在单个页面(例如index.html / jsp / whatever)上启动时为所有URL附加唯一标识符。 浏览器将使用所有选项卡上的相同cookie,因此放入cookie的所有内容都不会是唯一的。

我最近使用Cookies开发了一个解决这个问题的方法。 这是我的解决scheme的链接。 我还包括使用ASP.NET解决scheme的示例代码,如果需要,您应该可以将其适用于JSP或Servelets。

https://sites.google.com/site/sarittechworld/track-client-windows

Spring Session在同一浏览器中支持多个会话查看示例和实现细节http://docs.spring.io/spring-session/docs/current/reference/html5/guides/users.html

另一种可行的方法是创build一个唯一的窗口ID,并将该值与会话ID一起存储在数据库表中。 我经常使用的窗口ID是整数(现在)。 如果窗口被刷新,重新加载或提交给自己,则在打开窗口时重新创build此值。 窗口值(input)使用链接保存在本地表中。 当需要一个值时,根据窗口ID /会话ID链接从数据库表中获得。 虽然这种方法需要本地数据库,但实际上是十分简单的。 数据库表的使用对我来说很简单,但我没有看到为什么本地数组不能正常工作。

我一直在阅读这篇文章,因为我以为我想做同样的事情。 我正在处理的应用程序也有类似的情况。 实际上这是一个比实际更能体现testing的问题。

在阅读这些答案后,尤其是Michael Borgwardt给出的答案之后,我意识到需要存在的工作stream程:

  1. 如果用户导航到login屏幕,请检查现有会话。 如果存在,绕过login屏幕并将其发送到欢迎屏幕。
  2. 如果用户(在我的情况下)导航到注册屏幕,检查现有的会话。 如果存在,让用户知道你要logging该会话。 如果他们同意,注销,并开始注册。

这将解决用户在他们的会话中看到“另一个用户”的数据的问题。 他们并没有真正在他们的会话中看到“另一个用户”的数据,他们真的从唯一的会话中看到数据。 很明显,这会导致一些有趣的数据,因为某些操作会覆盖某些会话数据,而不是其他操作,因此您在该单个会话中有数据组合。

现在,解决testing问题。 唯一可行的方法是利用预处理器指令来确定是否应该使用无cookie会话。 通过针对特定环境构build特定的configuration,我可以对环境及其用途做出一些假设。 这将允许我在技术上同时login两个用户,并且testing人员可以从同一个浏览器会话中testing多个场景,而不必从任何这些服务器会话中注销。

但是,这种方法有一些严重的警告。 其中至less有一个事实是,testing人员正在testing什么不是将要在生产中运行的。

所以我想我必须说,这是一个坏主意。

在window.sessionStorage中存储timeStamp(如果尚未设置)。 这将为每个选项卡提供唯一的值(即使URL相同)

http://www.javascriptkit.com/javatutors/domstorage.shtml

https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage

希望这可以帮助。

 How to differ sessions in browser-tabs? 

在浏览器选项卡中区分会话最直接的方法是禁止您的特定域设置cookie。 这样,您可以从单独的选项卡分开会话。 假设您不接受来自此域名的cookies:www.xyz.com。 您打开标签1,login并开始浏览。 然后你打开Tab 2,你可以login为一个用户或不同的用户; 无论哪种方式,您将有一个会话与表格1分开。等等。

但是,当你控制客户端时,这当然是可能的。 否则,这里的人们所规定的解决scheme应该适用。

你需要做的

1-存储帐户列表的cookie

2-可选存储一个默认的cookie

对于每个账户,它的索引像acc1,acc2

4-放入url东西代表的帐户索引,如果没有,你会select默认的一个像谷歌邮箱domain.com/0/some-url >> 0这里代表的帐户的索引也可能需要知道如何使用urlwrite

5-select一个cookie的时候,根据你的urlpathselect它代表帐户的索引

问候

我看到很多具有客户端更改操作会话ID cookie的实现。 但一般来说,会话​​ID Cookie应该是HttpOnly,所以Java脚本不能访问,否则可能导致会话劫持通过XSS

注意:这里的解决scheme需要在应用程序devise阶段完成。 以后再做这个工程很难。

使用隐藏字段来传递会话标识符

为了这个工作,每个页面都必须包含一个表单:

 <form method="post" action="/handler"> <input type="hidden" name="sessionId" value="123456890123456890ABCDEF01" /> <input type="hidden" name="action" value="" /> </form> 

您的每一个行动,包括导航,张贴表单(适当地设置action )。 对于“不安全”的请求,你可以包含另一个参数,比如包含要提交的数据的JSON值:

 <input type="hidden" name="action" value="completeCheckout" /> <input type="hidden" name="data" value='{ "cardNumber" : "4111111111111111", ... ' /> 

由于没有cookie,每个标签将是独立的,并且不会在同一个浏览器中了解其他会话。

很多优点,特别是在安全方面:

  • 不依赖JavaScript或HTML5。
  • 从本质上防止CSRF 。
  • 不依赖于cookie,所以可以防止POODLE 。
  • 不容易受到会话固定 。
  • 可以防止后退button的使用,当您希望用户按照通过站点设置的path(这意味着有时可能会受到无序请求攻击的逻辑错误可以被阻止)时,这是可取的。

一些缺点:

  • 后退buttonfunction可能是需要的。
  • caching不是很有效,因为每个操作都是POST。

更多信息在这里 。

我解决了以下方法:

  • 我为窗口指定了一个名字,这个名字和连接资源是一样的。
  • 加上1来清除存储在cookie中的连接连接。
  • 我创build了一个函数来捕获所有的xmloutput响应,并以json格式分配sid和cookie。 我为每个window.name做这个。

这里的代码是:

 var deferred = $q.defer(), self = this, onConnect = function(status){ if (status === Strophe.Status.CONNECTING) { deferred.notify({status: 'connecting'}); } else if (status === Strophe.Status.CONNFAIL) { self.connected = false; deferred.notify({status: 'fail'}); } else if (status === Strophe.Status.DISCONNECTING) { deferred.notify({status: 'disconnecting'}); } else if (status === Strophe.Status.DISCONNECTED) { self.connected = false; deferred.notify({status: 'disconnected'}); } else if (status === Strophe.Status.CONNECTED) { self.connection.send($pres().tree()); self.connected = true; deferred.resolve({status: 'connected'}); } else if (status === Strophe.Status.ATTACHED) { deferred.resolve({status: 'attached'}); self.connected = true; } }, output = function(data){ if (self.connected){ var rid = $(data).attr('rid'), sid = $(data).attr('sid'), storage = {}; if (localStorageService.cookie.get('day_bind')){ storage = localStorageService.cookie.get('day_bind'); }else{ storage = {}; } storage[$window.name] = sid + '-' + rid; localStorageService.cookie.set('day_bind', angular.toJson(storage)); } }; if ($window.name){ var storage = localStorageService.cookie.get('day_bind'), value = storage[$window.name].split('-') sid = value[0], rid = value[1]; self.connection = new Strophe.Connection(BoshService); self.connection.xmlOutput = output; self.connection.attach('bosh@' + BoshDomain + '/' + $window.name, sid, parseInt(rid, 10) + 1, onConnect); }else{ $window.name = 'web_' + (new Date()).getTime(); self.connection = new Strophe.Connection(BoshService); self.connection.xmlOutput = output; self.connection.connect('bosh@' + BoshDomain + '/' + $window.name, '123456', onConnect); } 

我希望能帮助你

如果是因为每个选项卡将在应用程序中运行不同的stream程,并且将两个stream程混合导致出现问题,那么最好是“区分”会话对象,以便每个stream程将使用会话的不同区域

这个区域可以被简单地实现为每个stream都有不同的前缀,或者会话对象将保存多个映射(每个stream一个),并且使用这些映射而不是会话属性,最好的做法是扩展会话类用它代替。