Check if session exists JSF
Asked Answered
I

2

8

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

Impurity answered 15/11, 2011 at 22:43 Comment(0)
H
17

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>
Harrie answered 15/11, 2011 at 23:5 Comment(10)
I had a little doubt concerning this. I was asked to add a commandLink that says "Go to main page" but when I click on it, it goes first to the ViewExpired page and then I have to click again to go to the main page. How can I go directly to the main page without doble clicking the commandLink?Impurity
Make it a normal <h:outputLink> instead which sends a fresh GET request without the need for view state. You don't need to submit any data along by POST, right?Harrie
That solved the problem, but another one appeared. If I remain in the login-page the ViewExpiredException is also happening. How to avoid that?Impurity
Apparently the page is been served from browser cache instead of from server. You'd need to tell the browser to not cache those pages. You can do that with a filter, see also https://mcmap.net/q/18451/-faces-redirect-and-the-back-button-cause-other-links-to-work-incorrectly/157882Harrie
Ok. Read it. So I have to put this filter in the UserBean or where? Is it a separate class?Impurity
It's just a separate class. See also the code example in that answer.Harrie
Still got errors, I moved it to a new post, because maybe it's off topic. https://mcmap.net/q/18150/-disabling-browser-cache-jsf Thanks.Impurity
@Harrie Can you check this answer >> https://mcmap.net/q/17936/-check-if-session-exists-jsf ?Delatorre
a filter is used to handle the session timeout. so why doesn't the filter handle the ViewExpiredException when an ajax call is fired? Or is it not possible to handle this in filter and only using ExceptionHandler?Huihuie
@akshob: exceptions on ajax requests are by default not thrown, but returned as a special XML response. So, when using a filter instead of an exception handler, you can't get away with a simple try-catch, you'd basically need to capture the HTTP response being written, parse and determine its contents in order to see if an exception was thrown during an ajax request. This is plain clumsy. Just use the right tool for the job in first place.Harrie
A
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.

Agio answered 11/11, 2014 at 17:3 Comment(1)
U.V. as this helped me managing permissions but this is not answering the real question (managing expired views)Achondroplasia

© 2022 - 2024 — McMap. All rights reserved.