Как я могу вручную загрузить сеанс Java, используя JSESSIONID?
У меня есть сервлет, который обрабатывает многочастную форму. Сообщение фактически создается компонентом загрузки файлов Flash, встроенным в страницу. В некоторых браузерах POST-сгенерированный Flash-файл не содержит JSESSIONID, что делает невозможным загрузку определенной информации из сеанса во время публикации.
Компонент флэш-загрузки содержит информацию о cookie и сеансе в специальном поле формы. Используя это поле формы, я могу получить значение JSESSIONID. Проблема в том, что я не знаю, как использовать это значение JSESSIONID для ручной загрузки этого конкретного сеанса.
Редактировать - на основе решения ChssPly76 я создал следующую реализацию HttpSessionListener:
@Override
public void sessionCreated(final HttpSessionEvent se) {
final HttpSession session = se.getSession();
final ServletContext context = session.getServletContext();
context.setAttribute(session.getId(), session);
}
@Override
public void sessionDestroyed(final HttpSessionEvent se) {
final HttpSession session = se.getSession();
final ServletContext context = session.getServletContext();
context.removeAttribute(session.getId());
}
Который добавляет все сеансы в ServletContext как атрибуты, сопоставленные их уникальными идентификаторами. Вместо этого я мог бы поместить карту сессий в контекст, но это кажется излишним. Пожалуйста, оставьте любые мысли по этому решению. Затем я добавляю следующий метод в свой сервлет, чтобы разрешить сеанс по идентификатору:
private HttpSession getSession(final String sessionId) {
final ServletContext context = getServletContext();
final HttpSession session = (HttpSession) context.getAttribute(sessionId);
return session;
}
5 ответов
Нет API для получения сессии по идентификатору.
Однако вы можете реализовать прослушиватель сеансов в своем веб-приложении и вручную поддерживать карту сеансов с ключом по идентификатору (идентификатор сеанса можно получить с помощью session.getId ()). После этого вы сможете получить любой сеанс, который захотите (вместо того, чтобы обмануть контейнер и заменить текущий сеанс на него, как предлагали другие)
Если вы используете Tomcat, вы спрашиваете tomcat напрямую (но это ужасно). Бьюсь об заклад, есть другие хакерские решения для других веб-серверов.
Он использует экземпляр интерфейса "Менеджер" для управления сеансами. То, что делает это уродливым, - то, что я не нашел хороший общедоступный интерфейс, чтобы иметь возможность подключиться, поэтому мы должны использовать отражение, чтобы получить менеджера.
Ниже находится прослушиватель контекста, который захватывает этот менеджер при запуске контекста, а затем может быть использован для получения сеанса Tomcat.
public class SessionManagerShim implements ServletContextListener {
static Manager manager;
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
manager = getManagerFromServletContextEvent(sce);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
manager = null;
}
private static Manager getManagerFromServletContextEvent(ServletContextEvent sce) throws NoSuchFieldException, IllegalAccessException {
// Step one - get the ApplicationContextFacade (Tomcat loves facades)
ApplicationContextFacade contextFacade = (ApplicationContextFacade)sce.getSource();
// Step two - get the ApplicationContext the facade wraps
Field appContextField = ApplicationContextFacade.class.getDeclaredField("context");
appContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext)
appContextField.get(contextFacade);
// Step three - get the Context (a tomcat context class) from the facade
Field contextField = ApplicationContext.class.getDeclaredField("context");
contextField.setAccessible(true);
Context context = (Context) contextField.get(applicationContext);
// Step four - get the Manager. This is the class Tomcat uses to manage sessions
return context.getManager();
}
public static Session getSession(String sessionID) throws IOException {
return manager.findSession(sessionID);
}
}
Вы можете добавить это как слушатель в ваш web.xml, и он должен работать.
Тогда вы можете сделать это, чтобы получить сеанс.
Безопасный способ сделать это - установить идентификатор jsession в cookie - это гораздо безопаснее, чем установить его в URL.
Как только он установлен как cookie, вы можете получить сеанс обычным способом, используя
request.getSession();
method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09");
В спецификации сервлета нет пути, но вы можете попробовать:
установка cookie вручную в запросе Flash
или делать так, как предложил Тейлор Л, когда я набирал и добавлял параметр jsessionid путь к URI.
Оба метода привязывают ваше приложение к запуску в контейнере сервлета, который ведет себя как Tomcat; Я думаю, что большинство из них делают. Оба также потребуют, чтобы ваш апплет Flash запрашивал на странице файлы cookie, что может накладывать зависимость JavaScript.
Это действительно хороший пост. Одна потенциальная проблема, с которой я сталкиваюсь при использовании прослушивателя сеансов для продолжения добавления сеансов в контекст, заключается в том, что он может стать довольно толстым в зависимости от количества одновременных сеансов, которые у вас есть. И тогда вся дополнительная работа по настройке веб-сервера для слушателя.
Так как насчет этого для гораздо более простого решения. Я реализовал это, и это работает довольно хорошо. Таким образом, на странице, которая загружает объект флэш-загрузки, сохраните сеанс и sessionid в виде пары ключ-значение в объекте приложения, а затем передайте этот идентификатор сеанса на страницу загрузки в качестве параметра post. На странице загрузки, посмотрите, есть ли уже идентификатор сеанса в приложении, используйте этот сеанс, в противном случае получите тот из запроса. Кроме того, затем удалите этот ключ из приложения, чтобы сохранить все в чистоте.
На странице SWF:
application.setAttribute(session.getId(), session);
Затем на странице загрузки:
String sessid = request.getAttribute("JSESSIONID");
HttpSession sess = application.getAttribute(sessid) == null ?
request.getSession() :
(HttpSession)application.getAttribute(sessid);
application.removeAttribute(sessid);
Очень хорошее решение, ребята. Спасибо за это.