1

I have the following servlet where I'm injecting CDI bean

public class FBOAuthFilter implements Filter {
    @Inject 
    private Instance<LoginBean> loginBeanSource;


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
        FilterChain fc) throws IOException, ServletException {
        try{
           String code = request.getParameter("code");
           LoginBean loginBean = loginBeanSource.get();
           loginBean.doLogin(code);
        } catch(Exception ex){
           System.out.println("Exception");
        }
   }
}

CDI Bean:

@Named(value="loginbean")
@SessionScoped
public class LoginBean implements Serializable{



     public void doLogin(String code){
        //do something

        FacesContext context = FacesContext.getCurrentInstance();
        System.out.println(context == null);
        context.getExternalContext().redirect("somepage");

    }
}

However, when I try to access the FacesContext in the CDI Bean, its null. Is there a way to get access to the FacesContext ?

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
fareed
  • 3,034
  • 6
  • 37
  • 65
  • 1
    FacesContext is created in FacesServlet. Because filters are executed before servlets, FacesContext is not yet available. Why do you need FacesContext? Could you manage without it? – tuner Apr 27 '17 at 08:08
  • @tuner Most of my business logic is done in servlet filter, I can do a workaround and move everything to Faces Servlet instead, but I was wondering the possibilities of accessing FacesContext in the servlet-filter and get the actual instance of the CDI bean, not a proxy. – fareed Apr 29 '17 at 12:47

1 Answers1

2

This is not the correct approach.

All filters run before the servlet is hit. The FacesContext is only available when the FacesServlet is hit. So as long as the FacesServlet isn't hit yet, then the FacesContext isn't available yet. So it's always null in all filters.

You need to rewrite the code in such way that you can solely use the readily available request and response objects and CDI in the filter, without relying on the FacesContext. It appears that you only wanted to perform a redirect. The "plain vanilla" servlet way is:

response.sendRedirect("somepage");

In order to properly use that, simply split your LoginBean code into two new beans: one which doesn't anywhere use javax.faces.* stuff, and another one which requires javax.faces.* stuff. The one which doesn't anywhere use javax.faces.* stuff can then be shared by both the filter and the managed bean.

@Dependent
public class LoginBeanWithoutFacesContext implements Serializable {

    public void doLogin(String code) {
        // do something without faces context
    }
}

@Named
@SessionScoped
public class LoginBean implements Serializable {

     @Inject
     private LoginBeanWithoutFacesContext loginBeanWithoutFacesContext;

     public void doLogin(String code) {
         loginBeanWithoutFacesContext.doLogin(code);

         FacesContext context = FacesContext.getCurrentInstance();
         context.getExternalContext().redirect("somepage");
    }
}

Finally use the LoginBeanWithoutFacesContext one in your filter.

public class FBOAuthFilter implements Filter {

    @Inject 
    private LoginBeanWithoutFacesContext loginBeanWithoutFacesContext;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            String code = request.getParameter("code");
            loginBeanWithoutFacesContext.doLogin(code);
            response.sendRedirect("somepage");
        }
        catch (Exception e) {
            throw new ServletException(e);
        }
    }
}

That said, consider using JEE standard authentication or a well-established library rather than some homegrown authentication for the job you're apparently doing in LoginBeanWithoutFacesContext. See also How to handle authentication/authorization with users in a database?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I know there is a Q/A about (not!) doing businesslogic in filters. Cannot find it directly but it would be a good addition in this answers **'See also'** section – Kukeltje Apr 28 '20 at 10:10
  • @Kukeltje: That depends on the functional requirements. In this case it seems some sort of autologin by some sort of token which can appear on any arbitrary URL. It's not unreasonable to use a filter for the job. The login itself apparently being homegrown code rather than using an established library is in turn indeed often a poor practice. But this question technically isn't about that. – BalusC Apr 28 '20 at 10:51
  • Correct, I was more referring to the statement by OP that all the businesslogic was done in filters, not specifically the login part... – Kukeltje Apr 28 '20 at 11:14
  • @Kukeltje: Oh, in the comment on his question. Sorry, I didn't see that. Didn't seem relevant to the technical question. – BalusC Apr 28 '20 at 11:31