0

I need to do some checks before every page is loaded to see if there's a need to redirect the user to another page (for security reasons).

When I was using JSF 2.0 I used a phase listener to do this job. Now that I'm using JSF 2.2 and all my beans are not JSF beans anymore, but CDI beans, I think I'm offered better choices to do this (or not?).

I've heard of the viewAction event, but I wouldn't like to be repeating metadata on every page (only if there's no other option).

So what's the best approach to implement this scenario in JSF 2.2 with CDI?

UPDATE (after @skuntsel suggestion)

This is the filter that I'm using for now. I would like to use it only after authentication to simplify its code. By the way, if you can see any mistake in it, I would appreciate if you told me.

@WebFilter("/*")
public class SolicitacoesFilter implements Filter
{
    // I can't just use @Inject private User _user, because it needs to be initialized
    // only when the user is authenticated. Otherwise an exception is thrown. If this
    // filter was called only after the authentication I could use the mentioned code.
    private User _user;

    @Inject
    private Instance<User> _userGetter;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
    {
        if (initializeUser(request))
        {
            if (_user.isProvisoryPassword())
            {
                // Redirect to another page...
                return;
            }
            if (_user.getStatus() != Status.ACTIVE)
            {
                // Redirect to another page...
                return;
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy()
    {
    }

    private boolean initializeUser(ServletRequest request)
    {
        boolean userAuthenticated = ((HttpServletRequest) request).getUserPrincipal() != null;
        if (userAuthenticated)
        {
            if (_user == null)
            {
                _user = _userGetter.get();
            }
        }
        else
        {
            _user = null;
        }
        return _user != null;
    }
}
Marcos
  • 1,237
  • 1
  • 15
  • 31
  • 1
    In both JSF versions you mentioned a web filter is the preferred way! – skuntsel Aug 01 '13 at 18:03
  • I have a session scoped CDI bean that represents the user. I need to have access to it to do the check. So, can I access this CDI bean from the filter? Are filters allowed injection? – Marcos Aug 01 '13 at 18:07
  • 2
    `@WebFilter` is a valid injection target for a CDI bean via `@Inject`, but were it not, data would be of course accessible via HTTP session's attribute map. Related: http://stackoverflow.com/questions/7815308/how-do-i-get-a-sessionscoped-cdi-bean-from-inside-a-filter. – skuntsel Aug 01 '13 at 18:30

1 Answers1

0

Ok, what are the purposes of your redirection need ?

  • If it's about checking session User for authentification purposes, use filter:

Let's assume there is login form at : http://www.domain.com/login.jsf. Once the user fires connect button, we want to redirect him to http://www.domain.com/member/welcome.jsf, and avoid other people not to access the member/welcome.jsf domain, I mean all the pages which are in http://www.domain.com/member/....

Here a simple design:

@WebFilter("/member/*")  
public class SecurityCheck implements Filter {

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest req, ServletResponse res,
    FilterChain chain) throws ServletException, IOException {

  HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession session = request.getSession();

    if (session == null || session.getAttribute("User") == null) {
        response.sendRedirect(request.getContextPath() + "/index.xhtml"); // No logged-in user found, so redirect to login page.
    } else {
        chain.doFilter(req, res); // Logged-in user found, so just continue request.
    }

}

@Override
public void destroy() {
// Cleanup global variables if necessary.
}
  • Other case, use:

    <h:link></h:link>,or <h:commandLink></h:commandLink> // Checking in the managed Beans method
    
  • You can also xml file, for redirection.

Rollyng
  • 1,387
  • 2
  • 12
  • 18
  • No, it's for authorization porpuses, not authentication. So the filter checks only makes sense after the user is authenticated (I'm using FORM based authentication). So I had to use code like this in the filter to see if the user is authenticated: `boolean authenticated = ((HttpServletRequest) request).getUserPrincipal() != null`. By the way, is there a way to activate the filter only when the user is already authenticated? It would be nice if we could specify an _excluded_ url pattern for the filter as well. – Marcos Aug 02 '13 at 11:08
  • - "So the filter checks only makes sense after the user is authenticated", The filter also avoid unauthentificated people to access some speficic pages. - "is there a way to activate the filter only when the user is already authenticated?", for what user roles ? what are the purposes of your redirection need ? – Rollyng Aug 02 '13 at 12:07
  • I don't have the concern of unauthenticated people accessing some pages because, as I said, my web application is configured to use _FORM based authentication_, so the web container automatically takes care of this issue for me. That's why I would like to configure the filter to be called only when the user is authenticated. This way I don't need to check if the user is authenticated in the filter. – Marcos Aug 02 '13 at 12:14
  • Ok, my redirection needs (with an authenticated user): **(1)** check if the user has already changed his provisory password (the one that is first generated for him). If not, redirect to another page to allow him to change the password. **(2)** ckeck the user status. If his status is not ok, redirect to another page. All this only makes sense to authenticated users. – Marcos Aug 02 '13 at 12:18
  • I've just told you my redirection needs. – Marcos Aug 02 '13 at 12:21
  • Sorry, there weren't there, when i was answering (refresh issue?). I think you should prompt an alert message or highlighted text once connected, to remind him theses things, you don't need a filter for that purpose. To do that you just need to implement a boolean isAGeneratedPassword, and as long as "YES" prompts the message, with a simple link to a form where he could edit. – Rollyng Aug 02 '13 at 12:38
  • Unfortunately my application requirements demands this. The user has to change the password and be with a valid status. – Marcos Aug 02 '13 at 12:41