I have a login page where I have a User bean to authenticate username and password for a person. This Bean is Session Scoped. If someone writes a URL and tries to jump the login page, how can I check that and redirect him to the login page?

On the other hand. Suppose I have logged in and I was working and suddenly I go out for a while and my session expires. When I return and try to interact with the form it sends a message alerting me the session expiration. How can I redirecto again to the login form when this occurs?

Thanks in advance. Hope I explain myself.

Mojarra 2.1.4, Tomcat 7, Tomahawk 1.1.11


Solution 1:

If someone writes a URL and tries to jump the login page, how can I check that and redirect him to the login page?

You seem to using homegrown authentication. In that case, you need to implement a servlet filter. JSF stores session scoped managed beans as attributes of HttpSession, so you could just check on that in doFilter() method:

HttpServletRequest req = (HttpServletRequest) request;
UserManager userManager = (UserManager) req.getSession().getAttribute("userManager");

if (userManager != null && userManager.isLoggedIn()) {
    chain.doFilter(request, response);
} else {
    HttpServletResponse res = (HttpServletResponse) response;
    res.sendRedirect(req.getContextPath() + "/login.xhtml");
}

Map this filter on an URL pattern covering the secured pages, e.g. /app/*.


When I return and try to interact with the form it sends a message alerting me the session expiration. How can I redirect again to the login form when this occurs?

I understand that this concerns Ajax requests? For normal requests you could have used an <error-page> in web.xml. If setting the state saving method to client in web.xml as follows

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

is not an option, then you need to implement a custom ExceptionHandler:

public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    public ViewExpiredExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public void handle() throws FacesException {
        FacesContext facesContext = FacesContext.getCurrentInstance();

        for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) {
            Throwable exception = iter.next().getContext().getException();

            if (exception instanceof ViewExpiredException) {
                facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, "viewexpired");
                facesContext.renderResponse();
                iter.remove();
            }
        }

        getWrapped().handle();
    }

    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }

}

(note that this particular example navigates to viewexpired, so it expects a /viewexpired.xhtml as error page)

The above needs to be baked by the following ExceptionHandlerFactory implementation:

public class ViewExpiredExceptionHandlerFactory extends ExceptionHandlerFactory {

    private ExceptionHandlerFactory parent;

    public ViewExpiredExceptionHandlerFactory(ExceptionHandlerFactory parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getExceptionHandler() {
        return new ViewExpiredExceptionHandler(parent.getExceptionHandler());
    }

}

which in turn needs to be registered in faces-config.xml as follows:

<factory>
    <exception-handler-factory>com.example.ViewExpiredExceptionHandlerFactory</exception-handler-factory>
</factory>

Solution 2:

If you are implementing your own system you can add an attribute to user called session or whatever. This attribute can be boolean so whenever the session starts you can set this attribute to true. Write a method called permission for example:

public void permission() throws IOException {

        if(userStatelessBean.getSession() == false) {
            System.out.println("*** The user has no permission to visit this page. *** ");
            ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
            context.redirect("login.xhtml");
        } else {
            System.out.println("*** The session is still active. User is logged in. *** ");
        }
    }

On each of your jsf page (for this example) that you want to have restrictions on, you can add the following code at the very beginning of your page:

<f:metadata>
     <f:event type="preRenderView" listener="#{sesija.permission()}"/>
</f:metadata>

What this is going to do is call the JSF ManagedBean with object name sesija before rendering the page and check whether the rulles you've created in specified method are satisfied or not.

I hope you find this useful,

Thank you.