Как отличать сеансы в браузерах?

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

<%@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), введите свое имя на вкладке и отправьте форму. Затем откройте новую вкладку в том же браузере, а затем вы увидите свое имя (получить из сеанса) на новой вкладке. Будьте осторожны с кешем браузера, иногда кажется, что этого не происходит, но в кэше обновите вторую вкладку.

Спасибо.

Ответ 1

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

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

Ответ 2

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

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

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

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

Ответ 3

Свойство javascript window.name является единственной вещью, которая будет сохраняться в активности вкладок, но может оставаться независимой (вместо URL-адреса guff).

Ответ 4

Вы не должны.. Если вы хотите сделать это, либо вам нужно заставить пользователя использовать один экземпляр вашего приложения, написав URL-адреса "на лету", используя sessionID (не sessionid) он не будет работать) id и передать его в каждом URL-адресе.

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

Ответ 5

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

Используйте 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 - к сожалению, для этого случая - по умолчанию.) Есть другие способы справиться с этим случаем, например обнаруживая нажатия F5 и Ctrl + R/Alt + R, которые будут работать в большинстве случаев, но могут быть сорваны с помощью реконфигурации ярлыка пользовательской клавиатуры или использования альтернативной ОС. Тем не менее, это на самом деле кросс-кейс в действительности, и сценарии наихудшего случая никогда не бывают такими плохими: в конфигурации системы чести вы должны войти в систему как не тот человек (но вы можете сделать очевидным, что это случай, персонализируя страницы с цветами, стилями, заметно отображаемыми именами и т.д.); в конфигурации пароля, бремя на последнего человека, который ввел свой пароль, чтобы выходить из системы или делиться их сеансом, или если этот человек фактически является текущим пользователем, тогда нет нарушения.

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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

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

2) на каждой странице, которую вы используете (используйте глобальный файл или что-то еще), просто введите код для обнаружения события фокуса и/или события mouseover. (Я буду использовать 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;
}

серверная сторона (например, С#)

//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];

Готово.

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

Вы можете использовать переписывание ссылок для добавления уникального идентификатора ко всем вашим URL-адресам при запуске на одной странице (например, index.html/jsp/whatever). Браузер будет использовать одни и те же файлы cookie для всех ваших вкладок, поэтому все, что вы помещаете в файлы cookie, не будет уникальным.

Ответ 11

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

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

Ответ 13

Другим подходом, который работает, является создание уникального идентификатора окна и сохранение этого значения вместе с идентификатором сеанса в таблице базы данных. Идентификатор окна, который я часто использую, является целым (теперь). Это значение создается, когда окно открывается и повторно назначается в том же окне, если окно обновляется, перезагружается или отправляется самому себе. Значения окон (входы) сохраняются в локальной таблице, используя ссылку. Когда требуется значение, оно получается из таблицы базы данных на основе ссылки id/session id окна. Хотя для этого подхода требуется локальная база данных, он практически безупречен. Использование таблицы базы данных было легко для меня, но я не вижу причин, почему локальные массивы не будут работать так же хорошо.

Ответ 14

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

Прочитав эти ответы, особенно тот, который дал Майкл Боргвардт, я понял, какой поток работы должен существовать:

  • Если пользователь переходит на экран входа в систему, проверьте существующий сеанс. Если один из них обходит экран входа в систему и отправляет его на экран приветствия.
  • Если пользователь (в моем случае) перейдет на экран регистрации, проверьте существующий сеанс. Если таковая существует, сообщите пользователю, что вы собираетесь регистрировать этот сеанс. Если они согласятся, выйдут из системы и начнут регистрироваться.

Это позволит решить проблему, когда пользователь видит данные "другого пользователя" в своем сеансе. На самом деле они не видят "данные другого пользователя" в своей сессии, они действительно видят данные только с открытой сессии. Понятно, что это вызывает некоторые интересные данные, поскольку некоторые операции перезаписывают некоторые данные сеанса, а не другие, поэтому у вас есть комбинация данных за один сеанс.

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

Однако этот подход имеет некоторые серьезные оговорки. Не в последнюю очередь это тот факт, что тестер тестирует не, что будет запускаться в процессе производства.

Итак, я думаю, что я должен сказать, что это, в конечном счете, плохая идея .

Ответ 16

How to differ sessions in browser-tabs?

Самый простой способ разделить сеансы на вкладках браузера - запретить ваш конкретный домен для установки файлов cookie. Таким образом, вы можете иметь отдельные сеансы из отдельных вкладок. Предположим, вы запретили куки файлы из этого домена: www.xyz.com. Вы открываете вкладку 1, авторизуетесь и начинаете просмотр. Затем вы открываете Tab 2, и вы можете войти в систему как один и тот же пользователь или другой; в любом случае, у вас будет сеанс отдельно от Tab 1. И так далее.

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

Ответ 17

вам нужно будет

1- хранить список файлов cookie для учетных записей

2- необязательно хранить файл cookie по умолчанию

3- хранить для каждой учетной записи с индексом как acc1, acc2

4- введите в URL-адрес что-то, представляющее индекс учетных записей, и если вы не выберете значение по умолчанию например, google mail domain.com/0/some-url → 0 здесь представляют индекс учетной записи также вам может понадобиться знать, как использовать urlwrite

5- при выборе файла cookie выберите его в соответствии с вашим urlpath, указав индекс учетной записи

Привет

Ответ 18

Я вижу много реализаций, которые имеют изменения на стороне клиента, чтобы манипулировать куки-идентификаторами сеанса. Но в общем случае файлы cookie id должны быть HttpOnly, поэтому java- script не может получить доступ, иначе это может привести к захвату сеанса через XSS

Ответ 19

Примечание. Решение здесь должно быть выполнено на этапе разработки приложения. Трудно было бы это сделать позже.

Используйте скрытое поле для передачи идентификатора сеанса.

Для этого каждая страница должна содержать форму:

<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.
  • Незащищен фиксация сеанса.
  • Может предотвратить использование кнопки "Назад", что желательно, если вы хотите, чтобы пользователи следовали установленному пути через ваш сайт (что означает, что логические ошибки, которые иногда могут быть атакованы запросами вне порядка), могут быть предотвращены.

Некоторые недостатки:

  • Возможно, потребуется функция кнопки "Назад".
  • Не очень эффективен с кешированием, поскольку каждое действие является POST.

Дополнительная информация здесь.

Ответ 20

Я решил это следующим образом:

  • Я назначил имя для окна, это имя совпадает с именем ресурса соединения.
  • плюс 1, чтобы избавиться от сохранения в cookie для подключения.
  • Я создал функцию, чтобы захватить весь ответ xmloutput и назначить sid и избавиться от cookie в json-формате. Я делаю это для каждого 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('[email protected]' + 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('[email protected]' + BoshDomain + '/' + $window.name, '123456', onConnect);
    }

Я надеюсь помочь вам.

Ответ 21

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

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