Как я могу вручную загрузить сеанс 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);

Очень хорошее решение, ребята. Спасибо за это.

Другие вопросы по тегам