2

The problem: I am on some page of my application and go away for a while. Coming back and clicking on a link I get a "Unable to restore viewID" message. Same on hitting refresh.

I can start a new session, but I have to manually edit the URL as follows:

Active address window:

http://localhost:8080/myapp/index.xhtml?windowId=e9d

into

http://localhost:8080/myapp/index.xhtml

Then a new session is established, and the user has to log in again which is what I want.

In researching how to deal with this, I see a lot of "solutions" that basically keep the session alive by using client-side Javascript to send requests periodically to keep the session alive. Personally I do not consider this a desirable solution.

What I want is when the session times out, all subsequent requests to any non-public page needs to be directed to index.xhtml. References to pages that don't require login should go through with a new session object. Preferably this would be handled using only JSF 2 defined facilities, but I don't mind writing a Servlet filter if that is what it takes.

Can anyone provide a link to a how-to that I missed?

AlanObject
  • 9,613
  • 19
  • 86
  • 142

1 Answers1

4

Do it in a Filter, yes. You could use HttpServletRequest#getRequestedSessionId() to check if the client has sent a session cookie and HttpServletRequest#isRequestedSessionIdValid() to check if it is still valid (i.e. the session hasn't been expired in the server side):

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletRequest res = (HttpServletResponse) response;

    if (req.getRequestedSessionId() != null && !req.isRequestedSessionIdValid()) {
        res.sendRedirect(req.getContextPath() + "/index.xhtml");
    } else {
        chain.doFilter(request, response);
    }
}

But, that brings up another question, how exactly are you filtering logged-in users? If the session is expired, then the user is not logged-in anymore, right? You could instead also just check in the filter if the user is logged-in or not.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I am handling user authentication at the application level. There is a @SessionScoped bean called Login, and one of its properties is the User object which is null if the user is not logged in. I think I know how to fetch the managed bean from the filter so I can just modify your example code accordingly. Can I assume that the sendRedirect() call will abort any further processing of the request? – AlanObject Oct 17 '11 at 16:41
  • Yes, it will. All other filters/servlets (also the `FacesServlet`) is only invoked when you continue request/response by `chain.doFilter()`. Related: http://stackoverflow.com/questions/6883430/prevent-accessing-restricted-page-without-login-in-jsf2 – BalusC Oct 17 '11 at 16:44
  • I ran into some trouble with this solution because I need to access my session-scoped objects to determine authentication status. Getting access to the FacesContext object in a Filter is painful at best. Would it be possible/better to use a PhaseListener to do this instead? I am looking at your web page here: http://balusc.blogspot.com/2006/06/communication-in-jsf.html#AccessingTheFacesContextInsideHttpServletOrFilter – AlanObject Oct 18 '11 at 00:51
  • The filter runs before the `FacesServlet` runs. It hasn't created the `FacesContext` yet. Just get the session scoped managed bean as `HttpSession` attribute. JSF stores them over there. See also the "related" link in my previous comment for a concrete code example. – BalusC Oct 18 '11 at 01:34