I got an application using Primefaces 6.0 / JSF 2.2 in which i have the following scenario.
A use logs in by interacting with a @SessionScoped bean in the application and is redirected to the homepage.jsf. After that, the user navigates to a page through a menuitem (mypage.jsf).
public void login() throws IOException {
//.... Authentication mechanism here
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
externalContext.redirect(new StringBuilder(externalContext.getRequestContextPath())
.append("/homepage.jsf").toString());
return;
}
From the same tab, he then logs out from the application and is autmaticaly redirected to the login page.
public String logout() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.invalidateSession();
return "/login/login.jsf?faces-redirect=true";
}
Note: While the login/logout implementation is within a @SessionScoped handler, the rest of the application for its actions/redirections are @ViewScoped.
The user logs in again in the application and tries to navigate through the same p:menu item on the same page he was before (mypage.jsf)
<p:menuitem value="" url="/mypage.jsf?faces-redirect=true" />
At this point the application throughs a javax.faces.application.ViewExpiredException: View could not be restored . This behavior is described in mumerous posts in stackoverflow, with one of them giving detailed information about this behavior after an invalidation of the session (javax.faces.application.ViewExpiredException: View could not be restored)
Things i tried: I know this is not that much relevant and that on JSF 2.2 it is set on false by default, still gave it a try.
<context-param>
<param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
<param-value>false</param-value>
</context-param>
Setting manually the number of views in session. Note that only 1 or 2 users work on the application but set it just in case.
<context-param>
<description></description>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>15</param-value>
</context-param>
<context-param>
<description></description>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>15</param-value>
</context-param>
In addition, i have created a filter to avoid caching as mentioned also here Prevent user from seeing previously visited secured page after logout
@WebFilter(servletNames = { "facesServlet" })
public class LoginFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(request, response);
return;
}
}
I am a ware that setting javax.faces.STATE_SAVING_METHOD to client might solve my issue, but this is something i try to avoid.
In addition i have created an exception handler to handle a Viewexpireexception and redirect the user to a specific page. Of course this is just to handle such a situation and not solving the issue.
Update 1
I tried to use a commandLink with ajax set to false for the redirection on "mypage.jsf" just in case that was an issue but had exactly the same exception
<h:commandLink action="/mypagejsf?faces-redirect=true" ajax="false" value="My Link" />
Update 2 After loging out for the first time and analysing the request headers from the login page, i noticed following:
1) The sessionID on the browser matches with the one on the server
2) The Referer attribute shows to the following url http://..../mypage.jsf?faces-redirect=true . This is the page that i receive the exception when i try to access it.
Update 3 I also noticed, that when i try to access the mypage.jsf after a second login (before the exception occurs), my client requests (if i am not mistaken) with the same sessionId that exists also on the server. When the exception occurs, the session on the server is destroyed and a new session is created.