Как отличить сеансы в браузере-вкладках? - PullRequest
129 голосов
/ 15 декабря 2008

В веб-приложении, реализованном на Java с использованием JSP и сервлетов; если я храню информацию в пользовательском сеансе, эта информация передается со всех вкладок одного и того же браузера. Как отличить сеансы в браузере-вкладках? В этом примере:

<%@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), разверните этот файл в существующем контексте веб-приложения на сервере (я использую Apache Tomcat), затем откройте браузер (FF, IE7 или Opera), используя правильный URL (localhost/context1/testpage.jsp), введите свое имя в поле ввода и отправьте форму. Затем откройте новую вкладку в том же браузере, и тогда вы сможете увидеть свое имя (получить из сеанса) на новой вкладке. Будьте осторожны с кешем браузера, иногда кажется, что этого не происходит, но он находится в кеше, обновите вторую вкладку.

Спасибо.

Ответы [ 21 ]

86 голосов
/ 02 августа 2012

Вы можете использовать HTML5 SessionStorage (window.sessionStorage). Вы сгенерируете случайный идентификатор и сохраните его в хранилище сеанса на вкладке браузера. Тогда каждая вкладка браузера имеет свой собственный идентификатор.

Данные, сохраненные с помощью sessionStorage, не сохраняются на вкладках браузера, даже если две вкладки содержат веб-страницы из одного и того же домена. В Другими словами, данные внутри sessionStorage ограничены не только домен и каталог вызывающей страницы, но вкладка браузера в в которой содержится страница. Сравните это с файлами cookie сеанса, которые сохраняют данные от вкладки к вкладке.

22 голосов
/ 15 декабря 2008

Вы должны понимать, что сеансы на стороне сервера являются искусственным дополнением к HTTP. Поскольку HTTP не имеет состояния, сервер должен каким-то образом распознать, что запрос принадлежит конкретному пользователю, которого он знает и для которого существует сеанс. Есть 2 способа сделать это:

  • Cookies. Более чистый и популярный метод, но это означает, что все вкладки и окна браузера одним пользователем совместно используют сеанс - IMO, это на самом деле желательно, и я был бы очень раздражен на сайте, который заставил меня войти в систему для каждой новой вкладки, так как я очень интенсивно пользуйтесь вкладками
  • Перезапись URL. К любому URL на сайте добавлен идентификатор сеанса. Это больше работы (вы должны что-то делать везде, где у вас есть внутренняя ссылка на сайт), но позволяет иметь отдельные сеансы в разных вкладках, хотя вкладки, открытые по ссылке, все равно будут использовать сеанс. Это также означает, что пользователь всегда должен входить в систему, когда он заходит на ваш сайт.

Что ты пытаешься делать? Почему вы хотите, чтобы вкладки имели отдельные сессии? Может быть, есть способ достичь цели без использования сессий вообще?

Edit: Для тестирования могут быть найдены другие решения (например, запуск нескольких экземпляров браузера на отдельных виртуальных машинах). Если одному пользователю необходимо одновременно выполнять разные роли, тогда в приложении должна быть реализована концепция «роли», чтобы один логин мог иметь несколько ролей. Вам нужно решить, является ли это более приемлемым, с использованием перезаписи URL или просто с учетом текущей ситуации, поскольку просто невозможно обрабатывать вкладки браузера отдельно с помощью сеансов на основе файлов cookie.

16 голосов
/ 15 декабря 2008

Вы не должны. Если вы хотите сделать такую ​​вещь, либо вам нужно заставить пользователя использовать один экземпляр вашего приложения, записывая URL-адреса на лету, используя сессионный идентификатор, а не сессионный не сработает) Идентификатор и передать его в каждом URL.

Я не знаю, зачем вам это нужно, но если вам не нужно создать полностью непригодное приложение, не делайте этого.

16 голосов
/ 21 июня 2011

Свойство window.name Javascript - это единственное, что сохраняется при работе с вкладками, но может оставаться независимым (вместо разброса URL).

13 голосов
/ 16 июля 2009

Я придумала новое решение, которое имеет незначительные накладные расходы, но, похоже, работает как прототип. Одно из предположений заключается в том, что вы находитесь в системной среде чести для входа в систему, хотя это можно изменить, запрашивая пароль при каждом переключении вкладок.

Используйте localStorage (или эквивалентный) и событие хранилища HTML5, чтобы определить, когда новая вкладка браузера переключилась, какой пользователь активен. Когда это произойдет, создайте призрачное наложение с сообщением о том, что вы не можете использовать текущее окно (или временно отключите окно, возможно, вы не захотите, чтобы оно было таким заметным). Когда окно восстанавливает фокус, отправьте запись AJAX-запроса пользователь вернулся.

Одно предостережение об этом подходе: у вас не может быть никаких обычных вызовов AJAX (то есть тех, которые зависят от вашего сеанса), происходящих в окне, в котором нет фокуса (например, если у вас был вызов, происходящий после задержки ), если вы до этого не выполняли вызов AJAX для повторного входа в систему. Поэтому на самом деле все, что вам нужно сделать, это сначала проверить свою функцию AJAX, чтобы убедиться, что localStorage.currently_logged_in_user_id === window.yourAppNameSpace.user_id, и если нет, сначала войдите в систему с помощью AJAX.

Другое - это условия гонки: если вы можете переключать окна достаточно быстро, чтобы запутать его, вы можете получить последовательность relogin1-> relogin2-> ajax1-> ajax2, причем ajax1 выполняется в неправильном сеансе. Чтобы обойти эту проблему, отправьте запросы AJAX на массив в массив, а затем onstorage и перед отправкой нового запроса на вход прервите все текущие запросы.

Последнее, на что нужно обратить внимание - это обновления окна. Если кто-то обновит окно, когда у вас активен, но не выполнен запрос на вход в AJAX, он будет обновлен на имя не того человека. В этом случае вы можете использовать нестандартное событие beforeunload, чтобы предупредить пользователя о возможной путанице и попросить его нажать Отмена, в то же время повторно выполняя запрос входа в AJAX. Тогда единственный способ, которым они могут это испортить, - это нажать OK до завершения запроса (или случайно нажав Enter / пробел, потому что OK - к сожалению, для этого случая - по умолчанию.) Есть другие способы обработки этого случая, например обнаружение нажатий F5 и Ctrl + R / Alt + R, которые будут работать в большинстве случаев, но могут быть сорваны из-за перенастройки сочетания клавиш пользователя или альтернативного использования ОС. Тем не менее, это на самом деле немного крайний случай, и наихудшие сценарии никогда не бывают так плохи: в конфигурации системы чести вы будете зарегистрированы как неправильный человек (но вы можете сделать очевидным, что это случай путем персонализации страниц с цветами, стилями, заметными именами и т. д.); в конфигурации с паролем ответственность лежит на последнем человеке, который ввел свой пароль, чтобы выйти из системы или поделился своим сеансом, или, если этот человек на самом деле является текущим пользователем, нарушения не существует.

Но, в конце концов, у вас есть приложение «один пользователь на вкладку», которое (будем надеяться) просто действует как надо, без необходимости настраивать профили, использовать IE или переписывать URL-адреса. Убедитесь, что вы четко указываете на каждой вкладке, кто вошел в эту вкладку, хотя ...

10 голосов
/ 15 апреля 2014

У нас была эта проблема, и мы решили ее очень легко. Я имею в виду легко, потому что никакого программирования не участвует. Мы хотели позволить пользователю войти в несколько учетных записей в одном окне браузера, не конфликтуя между сеансами.

Таким образом, решение было случайных поддоменов.

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

Поэтому мы попросили нашего системного администратора настроить SSL-сертификаты для * .abc.com, а не для abc.com. Затем с небольшим изменением кода, каждый раз, когда пользователь пытается войти в систему, он попадает на вкладку со случайным номером субдомена. поэтому каждая вкладка может иметь свой собственный сеанс независимо. Также, чтобы избежать любых конфликтов, мы разработали случайное число, используя хэш или md5 идентификатора пользователя.

4 голосов
/ 15 октября 2013

Я буду честен здесь. , . все выше может или не может быть правдой, но все это кажется WAY слишком сложным или не учитывает знание того, какая вкладка используется на стороне сервера.

Иногда нам нужно применить бритву Оккама.

Вот подход Оккама: (нет, я не Оккам, он умер в 1347 году)

1) назначить уникальный идентификатор браузера вашей странице при загрузке. , , тогда и только тогда, когда у окна еще нет идентификатора (поэтому используйте префикс и обнаружение)

2) на каждой вашей странице (используйте глобальный файл или что-то еще) просто поместите код на место для обнаружения события фокуса и / или события наведения мыши. (Я буду использовать jquery для этой части, для простоты написания кода)

3) в функции фокуса (и / или наведения мыши) установите 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];

Готово.

2 голосов
/ 02 августа 2012

Я думаю, что вы, вероятно, хотите, чтобы поддерживать состояние навигации по вкладкам, а не специально создавать отдельный сеанс для каждой вкладки. Это именно то, чего достигает платформа Seam с их контекстом / контекстом беседы. Их реализация основана на том факте, что идентификатор диалога распространяется с каждым запросом и создает понятие диалога на стороне сервера, которое находится между сеансом и запросом. Это позволяет контролировать поток навигации и управление состоянием.

Хотя это в основном нацелено на JSF, взгляните и проверьте, можете ли вы взять из него некоторые идеи: http://docs.jboss.org/seam/latest/reference/en-US/html_single/#d0e3620

2 голосов
/ 05 октября 2012

В javascript, как я могу однозначно идентифицировать одно окно браузера из другого, которые находятся под одним и тем же идентификатором сессии на основе cookie

По существу используйте window.name. Если он не установлен, установите уникальное значение и используйте его. В разных вкладках, относящихся к одному и тому же сеансу, они будут разными.

1 голос
/ 07 января 2011

Недавно я разработал решение этой проблемы с помощью файлов cookie. Вот ссылка на мое решение. Я также включил пример кода решения с использованием ASP.NET, вы сможете адаптировать его к JSP или сервлетам, если вам нужно.

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

...