Search code examples
jsfauthenticationviewexpiredexception

jsf login times out


Ok simple question. I have a JSF application, containing a login page. The problem is if the user loads the login page, leaves it for a while, then tries to login the session expires and a ViewExpiredException is thrown. I could redirect back to the login when this happens, but that isn't very smooth. How can I allow this flow to properly login without an additional attempt?


Solution

  • Update

    As of Mojarra 2.1.19 / 2.2.0 you can now set the transient attribute of the <f:view> to true:

    <f:view transient="true">
         Your regular content
    </f:view>
    

    You can read about in on Balusc's blog here:

    http://balusc.blogspot.com.br/2013/02/stateless-jsf.html

    Original

    If you're using Facelets you can create your own ViewHandler to handle this:

    public class LoginViewHandler extends FaceletViewHandler
    {
        public LoginViewHandler( ViewHandler viewHandler )
        {
            super( viewHandler );
        }
    
        @Override
        public UIViewRoot restoreView( FacesContext ctx, String viewId )
        {
            UIViewRoot viewRoot = super.restoreView( ctx, viewId );
    
            if ( viewRoot == null && viewId.equals( "/login.xhtml" ) )
            {
                // Work around Facelet issue
                initialize( ctx );
    
                viewRoot = super.createView( ctx, viewId );
                ctx.setViewRoot( viewRoot );
    
                try
                {
                    buildView( ctx, viewRoot );
                }
                catch ( IOException e )
                {
                    log.log( Level.SEVERE, "Error building view", e ); 
                }
            }
    
            return viewRoot;
        }
    }
    

    Change "/login.xhtml" to your login page. This checks to see if it can restore your view, and if it cannot and the current view is your login page it will create and build the view for you.

    Set this in your face-config.xml as follows:

    <application>
        <!-- snip -->
        <view-handler>my.package.LoginViewHandler</view-handler>
    </application>
    

    If you're using JSF without Facelets (i.e. JSPs) you can try having the class extend ViewHandlerWrapper - note that buildView() will not be available. Hopefully createView() on it's own will set the view up correctly but I'm not 100% sure with JSF/JSP.