Перенаправление после истечения времени ожидания HttpSession

Я смотрел много сообщений по этой теме, но не смог найти решение, которое работает в моем случае.

Я использую Java EE 6 с JSF 2.0 (развернутый на JBoss AS 7.1)

В моем web.xml у меня есть:

    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>

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

что я пробовал:

Подход 1: использование фильтра

Я пробовал следующий фильтр:

@WebFilter()
public class TimeOutFilter implements Filter {

        @Override
        public void init(FilterConfig filterConfig) throws ServletException { 
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
        ServletException {
        System.out.println("filter called");
        final HttpServletRequest req = (HttpServletRequest) request;
        final HttpSession session = req.getSession(false);
        if (session != null && !session.isNew()) {
            chain.doFilter(request, response);
        } else {
            System.out.println("Has timed out");
            req.getRequestDispatcher("/logon.xthml").forward(request, response);
        }
    }

    @Override
    public void destroy() {
    }
}

В web.xml я пробовал

<filter-mapping>
    <filter-name>TimeOutFilter</filter-name>
    <url-pattern>*.xhtml</url-pattern>
</filter-mapping>

и

<filter-mapping>
    <filter-name>TimeOutFilter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

Фильтр работает так, как он вызывается при каждом запросе (ведение журнала "fiter called" в консоли). Однако он не вызывается, когда сеанс заканчивается.

Подход 2: HttpSessionLister

Я попытался использовать HttpSessionListerner. Метод, получивший следующую подпись:

public void sessionDestroyed(HttpSessionEvent se) {
}

Я не смог перенаправить на определенную страницу. Когда я хочу перенаправить пользователя, я обычно использую NavigationHandler из FacesContext, но в этом случае нет FacesContext (FacesContext.getCurrentInstance() возвращает null).

В соответствии с этим сообщением HttpListener не может перенаправить пользователя, потому что он не является частью запроса.

Вопрос

Каков наилучший способ решить эту проблему? Что я могу сделать, чтобы один из двух вышеупомянутых подходов работал?

Ответ 1

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

Основание на основе JavaScript на основе активности клавиатуры и мыши на клавиатуре, например, как указано здесь, или заголовка meta refresh, например, как ответ здесь было бы решением, если у вас в основном одностраничный webapp (таким образом, вы фактически не используете область сеанса, но область видимости), но это не сработает, открывать страницу в нескольких вкладках/окнах в том же сеансе.

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

Лучше всего просто определить страницу с ошибкой, которая касается случая, когда enduser вызывает действие во время истекшего сеанса. См. Также javax.faces.application.ViewExpiredException: просмотр не удалось восстановить.

Ответ 2

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

  • Вы можете использовать простой старый javascript для опроса: это будет работать в кросс-браузере.

    функция refresh() {

    // make Ajax call here, inside the callback call:
    
    setTimeout(refresh, 5000);
    
    // ...
    

    }

    // initial call, or just call refresh directly
    

    setTimeout (обновление, 5000);

  • Вы можете использовать веб-сокеты. Спецификация веб-сокета присутствует по ссылке ниже:

    http://dev.w3.org/html5/websockets/

Ответ 3

Я понимаю, что вы используете java-EE6 и JSF, но если вы можете попробовать использовать JSP-код или преобразовать этот код ниже для работы в сервлете. Предполагая, что вы используете имя пользователя для проверки сеанса, после установки тайм-аута сеанса в файле web.xml. Обратите внимание, что код JSP и код сервлета похожи. Ваш код для проверки сеанса может выглядеть следующим образом: (JSP Format)  Если имя пользователя является основным ключом в вашей базе данных.

 <%
    String un = (String)session.getAttribute("un");

    if(un == null){
   response.sendRedirect(login page);
   return;
}else{
      code to process login form
}
    %>

Код сервлета может выглядеть так:

String un = (String)session.getAttribute("un");
if(un == null){
   response.sendRedirect(loginPage);
}

Ответ 4

Вы можете использовать фильтр и выполнить следующий тест:

HttpSession session = request.getSession(false);
if(session != null && !session.isNew()) {
    chain.doFilter(request, response);
}
 else {enter code here
    response.sendRedirect("/login.jsp");
 }