10

我一直在查看有关此主题的许多帖子,但找不到适合我的解决方案。

我正在使用带有 JSF 2.0 的 Java EE 6(部署在 JBoss AS 7.1 上)

在我的web.xml我有:

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

希望在会话自动超时时将用户重定向到登录页面。

我尝试过的:

方法一:使用过滤器

我尝试了以下过滤器:

@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”)。但是,会话超时时不会调用它。

方法二:HttpSessionLister

我曾尝试使用HttpSessionListerner. 调用的方法具有以下签名:

public void sessionDestroyed(HttpSessionEvent se) {
}

我无法重定向到特定页面。当我想重定向用户时,我通常使用NavigationHandlerfrom ,FacesContext但在这种情况下没有FacesContextFacesContext.getCurrentInstance()返回null)。

根据这篇文章, HttpListener 无法重定向用户,因为它不是请求的一部分。

问题

解决这个问题的最佳方法是什么?我该怎么做才能使上述两种方法之一起作用?

4

4 回答 4

18

只要客户端没有发送 HTTP 请求,您就无法发送 HTTP 响应。就那么简单。这就是 HTTP 的工作原理。如果任何网站能够在没有客户端请求的情况下不经意地推送 HTTP 响应,那么 Internet 看起来会非常不同。

如果您基本上是单页 web 应用程序,则基于客户端键盘/鼠标活动的基于 JavaScript 的心跳(如在此处回答)或元refresh标头(如在此处回答)将是解决方案(因此,您实际上没有使用会话范围但视图范围),但如果您在同一会话中的多个选项卡/窗口中打开页面,则效果不佳。

从理论上讲,Websockets 是向客户端推送内容的正确解决方案,但这又需要一个活动会话。鸡蛋问题。此外,它不适用于目前仍然相对广泛使用的旧浏览器,因此它目前应该仅用于渐进增强。

最好的办法是只定义一个错误页面来处理最终用户在会话过期时调用操作的情况。另请参阅javax.faces.application.ViewExpiredException:无法恢复视图

于 2013-03-22T15:01:53.087 回答
0

在 HttpSessionListerner 中,您不能向用户发送任何响应。实现此目的的一种好方法是轮询,浏览器定期发送 HTTP 请求并立即收到响应。
有很多方法可以做到这一点:

  1. 您可以使用普通的旧 javascript 进行轮询:这将在跨浏览器环境中工作。

    函数刷新(){

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

    }

    // initial call, or just call refresh directly
    

    设置超时(刷新,5000);

  2. 您可以使用 Web 套接字。Web 套接字规范位于以下链接:

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

于 2013-08-06T05:20:26.103 回答
-1

我知道您正在使用 java-EE6 和 JSF,但如果您可以尝试使用 JSP 代码或将下面的代码转换为在 servlet 中工作。假设您使用用户名检查会话,在 web.xml 文件中设置会话超时后。请注意 JSP 代码和 servlet 代码相似。您的会话验证代码可能如下所示。(JSP 格式)如果用户名用作数据库中的主键。

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

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

Servlet 代码可能如下所示

String un = (String)session.getAttribute("un");
if(un == null){
   response.sendRedirect(loginPage);
}
于 2013-08-03T16:43:35.997 回答
-1

您可以使用过滤器并执行以下测试:

HttpSession session = request.getSession(false);
if(session != null && !session.isNew()) {
    chain.doFilter(request, response);
}
 else {enter code here
    response.sendRedirect("/login.jsp");
 }
于 2015-08-14T06:52:05.077 回答