0

When my session is expired in my Java EE 7, JSF web app.

I get a ViewExpiredException in ajax requests.

I would like to redirect to a page where it shows the user that the session is expired.

I tried browsing google and stackoverflow for a solution, but I didden't have any luck to get it to work with how I want it.

UPDATE:

I tried the solution posted @ Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request

It did work at my login page, when using the login_submit button.

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:p="http://primefaces.org/ui"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    template="./../templates/login_template.xhtml">

    <ui:define name="title">
        <h:outputText value="#{bundle.login_title}"/>
    </ui:define>

    <ui:define name="content">
        <h:outputText escape="false" value="#{bundle.login_message}"/>
        <h:form>
            <h:panelGrid columns="2" cellpadding="5">
                <h:outputLabel for="username" value="#{bundle.login_username}"/>
                <p:inputText id="username" type="text" value="#{authBean.username}" label="username"/>
                <h:outputLabel for="password" value="#{bundle.login_password}"/>
                <p:inputText id="password" type="password" value="#{authBean.password}"  label="password"/>
                <h:outputText value="#{bundle.login_invalid_password}" rendered="#{!authBean.validPassword and authBean.validUsername}"/>
                <h:outputText value="#{bundle.login_invalid_username}" rendered="#{!authBean.validUsername}"/>
                <p:commandButton value="#{bundle.login_submit}" action="#{authBean.doLogin}"/>
            </h:panelGrid>
        </h:form>
    </ui:define>

</ui:composition>

But it doesn't work with this JSF in a xhtml page that is on a secure page, login page is a public page. For example the following xhtml is on a secure page:

<p:commandButton styleClass="button #{chartBean.isViewButtonActive('MONTH')}" update="dataChart dataTable @form" value="#{bundle.performance_year}" action="#{chartBean.changeModel('MONTH')}" />

This does an AJAX post request, but it gets catched by my @WebFilter. (It also happends with selectOneMenu from Primefaces) This filter checks if an user is logged in if not it redirects them to the login page. But for some reason with the example button I given above it also get catched by the @WebFilter and the ajax requests gets as response redirect specified in the @WebFilter. It doesn't get catched by the ExceptionHandler. The @WebFilter is only applied to secure pages, see below.

@WebFilter(
        filterName = "AuthorizationFilter",
        urlPatterns = {"/secure/*"},
        dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}
)
public class AuthorizationFilter implements Filter {

Does anyone know how to solve this.

Community
  • 1
  • 1
Wesley Egbertsen
  • 720
  • 1
  • 8
  • 25

1 Answers1

3

I do it like this in the webfilter, and it works fine:

    // Check if user logged in, if not redirect to login.xhtml
    if (loginBean == null || !((LoginBean) loginBean).isLoggedIn()) {
        boolean isAjax = "XMLHttpRequest".equals(req.getHeader("X-Requested-With"));

        if (!isAjax) {
            res.sendRedirect(req.getContextPath() + "/login.xhtml"); 
        } else {
            // Redirecting an ajax request has to be done in the following way:
            // http://javaevangelist.blogspot.com/2013/01/jsf-2x-tip-of-day-ajax-redirection-from.html
            String redirectURL = res.encodeRedirectURL(req.getContextPath() + "/login.xhtml");
            StringBuilder sb = new StringBuilder();
            sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"").append(redirectURL).append("\"></redirect></partial-response>");
            res.setCharacterEncoding("UTF-8");
            res.setContentType("text/xml");
            PrintWriter pw = response.getWriter();
            pw.println(sb.toString());
            pw.flush();
        }
    } else {
        // Let chain of filters continue;
        chain.doFilter(request, response);
    }

Inspiration

Jaqen H'ghar
  • 4,305
  • 2
  • 14
  • 26
  • @Wesley Egbertsen Sorry that was not my real code, it is posted now... Could you please check if it is fine for you too? If I remember correctly I ran into problems with detecting if it was an ajax request with the previous code – Jaqen H'ghar Oct 16 '15 at 07:55
  • 1
    I already had a own function for detecting if it was a Ajax Request, I was getting really close to a solution, but the part from your code where you return a partial response with a redirect saved me! Here is how I check if it's an AJAX request: `private boolean isAJAXRequest(ServletRequest request) { HttpServletRequest req = (HttpServletRequest) request; return req.getHeader("faces-request") != null && req.getHeader("faces-request").toLowerCase().indexOf("ajax") > -1; }` – Wesley Egbertsen Oct 16 '15 at 09:39