I have been looking at many posts on this topic but couldn't get a solution that works in my case.
I am using Java EE 6 with JSF 2.0 (deployed on JBoss AS 7.1)
In my web.xml
I have:
<session-config>
<session-timeout>1</session-timeout>
</session-config>
and I want the user to be redirected to the login page when the session automatically times out.
what I have tried:
Approach 1: using filter
I have tried the following filter:
@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() {
}
}
In the web.xml
I have tried
<filter-mapping>
<filter-name>TimeOutFilter</filter-name>
<url-pattern>*.xhtml</url-pattern>
</filter-mapping>
and
<filter-mapping>
<filter-name>TimeOutFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
The filter works as it is called on every request (logging of "fiter called" in the console). However it is not called when the session times out.
Approach 2: HttpSessionLister
I have tried to use a HttpSessionListerner
. The method called having the following signature:
public void sessionDestroyed(HttpSessionEvent se) {
}
I wasn't able to redirect to a specific page. When I want to redirect a user I usually use the NavigationHandler
from the FacesContext
but in this case there is no FacesContext
(FacesContext.getCurrentInstance()
returns null
).
According to this post, the HttpListener cannot redirect the user because it is not part of a request.
Question
What is the best way to go to solve this problem? What can I do to make one of the two above-mentioned approaches to work?
You could use a Filter and do the following test:
I understand that you are using java-EE6 and JSF,but if you could try using JSP code or convert this code below to work in a servlet. Assuming you are using the username to check for session,after setting the session-timeout in the web.xml file.Please note that JSP code and servlet code are similar. Your code for validating of session could look like this.(JSP Format) If the username serves as the primary key in your database.
Servlet code could look like this
In HttpSessionListerner you cannot send any response to User. One good way to achieve this is with polling, the browser sends HTTP requests at regular intervals and immediately receives a response.
There are many ways to do that:
You can use plain old javascript to poll: This will work in cross browser environment.
function refresh() {
}
setTimeout(refresh, 5000);
You can use Web Sockets. Web socket specification is present on below link:
http://dev.w3.org/html5/websockets/
You can't send a HTTP response as long as the client hasn't send a HTTP request. Simple as that. That's just how HTTP works. The Internet would otherwise have looked very different if any website was able to unaskingly push a HTTP response without the client having requested for it.
A JavaScript based heartbeat based on client's keyboard/mouse activity like as answered here, or a meta
refresh
header like as answered here would be the solution if you've basically a single-page webapp (thus, you're effectively not using the session scope but the view scope), but that won't work nicely if you've the page open in multiple tabs/windows in the same session.Websockets is in theory the right solution to push something to the client, but this requires in turn an active session. Chicken-Egg problem. Also, it wouldn't work in older browsers currently still relatively widely in use, so it should currently merely be used for progressive enhancement.
Your best bet is to just define an error page which deals with the case when the enduser invokes an action while the session is expired. See also javax.faces.application.ViewExpiredException: View could not be restored.