Reputation: 53
I am confused about how sessions are managed in JSF 2.0.
I created 4 pages with login, data, info and sessionexpires that shows once session has expired.
When I click on logout button, it invalidates session by calling the following action method:
public String logout(){
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "logout?faces-redirect=true";
}
The code redirects me to logout page, as expected, but when I click browser's back button it takes me to the data page and shows all info, but i think, if session has already expired then it should show sessionexpires page.
How can I achieve the desired functionality?
Upvotes: 0
Views: 13804
Reputation: 11742
The fact that you see previous pages when user clicks browser's back button indicates that the pages were cached and are displayed from browser's cache rather that requested from server. To fix it you need to set HTTP response headers appropriately. This has been answered beforehand in Making sure a web page is not cached, across all browsers. Just to repeat BalusC, these are:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
The most appropriate place to set these headers is a web filter, as you don't seem to need any of JSF belongings there. You can find more information in the answers to Avoid back button on JSF web application. To repeat BalusC's code, you'll have:
@WebFilter("/secured/*")
public class NoCacheFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(req, res);
}
// ...
}
Just don't forget to tell which pages you need to filter. This way the new pages requested will always be sent from server and won't be cached anymore. So, if user tries to access a secured page after logout happened (by means of session invalidation and sending a redirect), your standard security means will kick in (other filter) preventing user from gaining access to those pages.
The next thing to do is to explain JSF how to deal with the already opened pages when session was invalidated / timed out. In other words, how can you deal with ViewExpiredException
s. This is in turn answered in How to handle session expiration and ViewExpiredException in JSF 2? and javax.faces.application.ViewExpiredException: View could not be restored for synchronous POST requests and in Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request for AJAX requests.
Basically, for the former you need to add the following lines to your web.xml:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/expired.xhtml</location>
</error-page>
For the latter I warmly recommend you to take a look at JSF utility library OmniFaces and its FullAjaxExceptionHAndler that was designed for this purpose.
Upvotes: 4