Unable to autowire the service inside my authentication filter in Spring

JavaSpringHibernateSpring Mvc

Java Problem Overview


I am trying to authenticate user by token, But when i try to auto wire one my services inside the AuthenticationTokenProcessingFilter i get null pointer exception. because autowired service is null , how can i fix this issue ?

My AuthenticationTokenProcessingFilter class

@ComponentScan(basePackages = {"com.marketplace"})
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
	
	@Autowired
	@Qualifier("myServices")
	private MyServices service;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        @SuppressWarnings("unchecked")
        Map<String, String[]> parms = request.getParameterMap();

        if (parms.containsKey("token")) {
        	try {
        		String strToken = parms.get("token")[0]; // grab the first "token" parameter
            	
            	User user = service.getUserByToken(strToken);
            	System.out.println("Token: " + strToken);
            	
            	DateTime dt = new DateTime();
    			DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    			DateTime createdDate = fmt.parseDateTime(strToken);
    			Minutes mins = Minutes.minutesBetween(createdDate, dt);
    			
            	
                if (user != null && mins.getMinutes() <= 30) {
                    System.out.println("valid token found");
                    
                    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

                    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword());
                    token.setDetails(new WebAuthenticationDetails((HttpServletRequest) request));
                    Authentication authentication = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword(), authorities); //this.authenticationProvider.authenticate(token);
                    
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }else{
                    System.out.println("invalid token");
                }
        	} catch(Exception e) {
        		e.printStackTrace();
        	}
        } else {
            System.out.println("no token found");
        }
        // continue thru the filter chain
        chain.doFilter(request, response);
    }
}

I Tried adding follwing in my AppConfig

@Bean(name="myServices")
    public MyServices stockService() {
        return new MyServiceImpl();
    }

My AppConfig Annotations are

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {

Java Solutions


Solution 1 - Java

You cannot use dependency injection from a filter out of the box. Although you are using GenericFilterBean your Servlet Filter is not managed by spring. As noted by the javadocs

> This generic filter base class has no dependency on the Spring > org.springframework.context.ApplicationContext concept. Filters > usually don't load their own context but rather access service beans > from the Spring root application context, accessible via the filter's > ServletContext (see > org.springframework.web.context.support.WebApplicationContextUtils).

In plain English we cannot expect spring to inject the service, but we can lazy set it on the first call. E.g.

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
	private MyServices service;
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		if(service==null){
			ServletContext servletContext = request.getServletContext();
			WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
			service = webApplicationContext.getBean(MyServices.class);
		}
        your code ...    
	}

}

Solution 2 - Java

It's an old enough question, but I'll add my answer for those who like me google this issue.

You must inherit your filter from GenericFilterBean and mark it as a Spring @Component

@Component
public class MyFilter extends GenericFilterBean {

    @Autowired
    private MyComponent myComponent;

 //implementation

}

And then register it in Spring context:

@Configuration
public class MyFilterConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Autowired
    private MyFilter myFilter;

    @Bean
    public FilterRegistrationBean myFilterRegistrationBean() {
        FilterRegistrationBean regBean = new FilterRegistrationBean();
        regBean.setFilter(myFilter);
        regBean.setOrder(1);
        regBean.addUrlPatterns("/myFilteredURLPattern");

        return regBean;
    }
}

This properly autowires your components in the filter.

Solution 3 - Java

I just made it work by adding

SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

I am unsure why we should do this even when i tried adding explicit qualifier. and now the code looks like

public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
    	
    	SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    	
        @SuppressWarnings("unchecked")
        Map<String, String[]> parms = request.getParameterMap();

        if (parms.containsKey("token")) {

Solution 4 - Java

If your filter class extends GenericFilterBean you can get a reference to a bean in your app context this way:

public void initFilterBean() throws ServletException {

@Override
public void initFilterBean() throws ServletException {

        WebApplicationContext webApplicationContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        //reference to bean from app context
        yourBeanToInject = webApplicationContext.getBean(yourBeanToInject.class);

        //do something with your bean
        propertyValue = yourBeanToInject.getValue("propertyName");
}

And here is less explicit way for those who doesn't like hardcoding bean names or need to inject more than one bean reference into the filter:

@Autowired
private YourBeanToInject yourBeanToInject;

@Override
public void initFilterBean() throws ServletException{

    SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());

    //do something with your bean
    propertyValue = yourBeanToInject.getValue("propertyName");
}

Solution 5 - Java

You can configure your bean filter and pass as a parameter whatever you need. I know out of Spring context where the filter it is, you cannot get the dependency injection that the auto-scan of spring does. But not 100% sure if there´s a fancy annotation that you can put in your filter to do some magic stuff

   <filter>
   <filter-name>YourFilter</filter-name>
       <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

<filter-mapping>
   <filter-name>YourFilter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>

and then inject bean in the spring.xml

  <bean id="YourFilter" class="com.YourFilter">
     <property name="param">
        <value>values</value>
     </property>
  </bean>

Solution 6 - Java

I am late to the party but this solution worked for me.

Add a ContextLoaderListener in web.xml. applicationContext can have dependency beans.

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

Then add in MyFilter SpringBeanAutowiringSupport processInjectionBasedOnServletContext which will add the webapplicationcontext into the filter which will add all the dependencies.

@Component
public class MyFilter implements Filter {

    @Autowired
    @Qualifier("userSessionServiceImpl")
    private UserSessionService userSessionServiceImpl;

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain 
    chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) req;
        if (userSessionServiceImpl == null) {
		    ServletContext context = httpRequest.getSession().getServletContext();
		SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, context);
	}
    
       .... (for brevity)
    }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRaghu ChandraView Question on Stackoverflow
Solution 1 - JavaHaim RamanView Answer on Stackoverflow
Solution 2 - JavaYuriy KovalekView Answer on Stackoverflow
Solution 3 - JavaRaghu ChandraView Answer on Stackoverflow
Solution 4 - JavaIgor VashView Answer on Stackoverflow
Solution 5 - JavapaulView Answer on Stackoverflow
Solution 6 - Javauser9059436View Answer on Stackoverflow