Конфликт JSESSIONID между двумя серверами с одним и тем же IP-адресом, но разными портами

У меня есть ситуация, когда у меня есть два разных веб-приложения, работающих на одном сервере с использованием разных портов. Они оба используют контейнер сервлетов Java Jetty, поэтому они оба используют параметр cookie с именем JSESSIONID для отслеживания идентификатора сеанса. Эти два веб-приложения борются за идентификатор сеанса.

  • Откройте вкладку Firefox и перейдите в WebApp1.
  • HTTP-ответ WebApp1 имеет заголовок set-cookie с JSESSIONID=1.
  • Firefox теперь имеет заголовок Cookie с JSESSIONID=1 во всех своих HTTP-запросах к WebApp1.
  • Откройте вторую вкладку Firefox и перейдите в WebApp2.
  • HTTP-запрос к WebApp2 также имеет заголовок Cookie с JSESSIONID=1, но в doGet, когда я вызываю req.getSession(false);, я получаю null. И если я вызову req.getSession(true), я получу новый объект Session, но тогда ответ HTTP от WebApp2 будет иметь заголовок set-cookie с JSESSIONID=20.
  • Теперь у WebApp2 есть рабочий сеанс, но сеанс WebApp1 отсутствует. Переход к WebApp1 даст мне новый сеанс, сметая сеанс WebApp2.
  • Продолжить навсегда

Таким образом, сеансы бьются между каждым веб-приложением. Мне бы очень хотелось, чтобы req.getSession(false) возвращал действительный сеанс, если уже определен файл cookie JSESSIONID.

Один из вариантов состоит в том, чтобы в основном переопределить инфраструктуру сеанса с помощью HashMap и файлов cookie с именами WEBAPP1SESSIONID и WEBAPP2SESSIONID, но это отстой, и это означает, что мне придется взломать новый материал Session в ActionServlet и в нескольких других местах.

Это должно быть проблемой, с которой столкнулись другие. HttpServletRequest.getSession(boolean) Джетти просто дерьмовый?


person Steve Armstrong    schedule 17.07.2009    source источник


Ответы (6)


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

Через некоторое время я пришел к следующему:

  • Подождите, пока причал инициализируется
  • используйте SocketManager причала, чтобы получить порт (socketManager.getLocalPort())
  • установить имя файла cookie через SessionManager (sessionHandler.getSessionManager().setSessionCookie(String))

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

person Moritz Both    schedule 09.06.2010

Проблема не в Jetty, а в том, как была определена спецификация cookie. Помимо пары имя/значение, файл cookie может также содержать дату истечения срока действия, путь, доменное имя и информацию о том, является ли файл cookie безопасным (т. е. предназначенным только для SSL-соединений). Номер порта не указан выше ;-), поэтому вам нужно будет изменить либо путь, либо домен, как говорит stepancheg в своем ответе.

person Vinay Sajip    schedule 18.07.2009
comment
Моя проблема в том, что когда Jetty создает новый сеанс, по умолчанию он даже не пытается использовать существующее значение JSESSIONID. Он просто выбирает новое значение для него. Если бы он повторно использовал существующие, то мои два экземпляра Jetty могли бы работать хорошо. - person Steve Armstrong; 20.07.2009

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

В context.xml сделайте что-то вроде

<Context sessionCookieName="JSessionId_8080">
person aij    schedule 23.10.2015

Я копался и обнаружил, что в AbstractSessionManager есть метод под названием getCrossContextSessionIDs(). Если он возвращает true, то при создании нового сеанса Jetty сначала проверит, установлен ли JSESSIONID, и попытается использовать этот существующий идентификатор сеанса. Я думаю, что могу установить значения true, используя какое-то свойство java при запуске.

При дальнейшем копании это поможет мне, только если я запускаю два веб-приложения в разных контекстах одного и того же Jetty (следовательно, кросс-контекст). При создании нового объекта Session выбирается новое значение JSESSIONID. Если getCrossContextSessionIDs() возвращает true, то он проверит, было ли текущее значение JSESSIONID создано этим Jetty (включая все другие контексты), и если это так, он повторно использует его.

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

person Steve Armstrong    schedule 20.07.2009
comment
Похоже, вам придется придерживаться Jetty - я не думаю, что это решение будет работать с другими контейнерами сервлетов. Надеюсь, вам никогда не придется переключаться :-) - person Vinay Sajip; 20.07.2009
comment
Ты прав. Мы рассматриваем изменение кода Jetty как краткосрочное решение. В долгосрочной перспективе мы либо реализуем собственное управление сеансами с использованием разных файлов cookie, либо все изменится, когда мы внедрим систему SSO. - person Steve Armstrong; 21.07.2009

Это правильное поведение. Вы можете разместить два своих веб-приложения в разных доменах или разными путями.

person stepancheg    schedule 17.07.2009

Я думаю, вы также можете установить путь к файлу cookie jsessionid.

person John Doe    schedule 18.07.2009