8

I need to use autowired in a filter. So i annotate my filter class using @Component,

import org.springframework.web.filter.GenericFilterBean;
@Component
public class TokenAuthorizationFilter extends GenericFilterBean {
    @Autowired
    public EnrollCashRepository enrollCashRepository;
}

Then i add my filter as below in SecurityConfig,

   @Configuration
    @EnableWebMvcSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        public void configure(WebSecurity webSecurity) throws Exception
        {
            webSecurity.ignoring().antMatchers(HttpMethod.GET, "/health");
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.addFilterBefore(new TokenAuthorizationFilter(), BasicAuthenticationFilter.class);  
            http.authorizeRequests().antMatchers("/api/**").authenticated();    
    }

My problem is my filter get invoked twice with the @Component annotation. If i remove the @Component annotation it only invoke once.

Then i add below as a fix in my Spring boot main class. Then i comment the line of addFilterBefore in SecurityConfig.

 @Bean
    public FilterRegistrationBean tokenAuthFilterRegistration() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new PITokenAuthorizationFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }

But then my filter get invoked once. But even i make the setEnabled true or false, i get a 403 Forbiddon Error when i invoke my rest api, http://localhost:8080/api/myservice

How can i fix this situation where i can use @Autowired in my Spring Filter?

Edit: Add controller and Filter class,

@RestController
@RequestMapping(value = "/api")
public class SpringToolController { 
    @RequestMapping(value = "/myservice", method = RequestMethod.GET)
    public HttpEntity<String> myService() {
        System.out.println("-----------myService invoke-----------");
        return new ResponseEntity<String>(HttpStatus.OK);
    }
}



public class TokenAuthorizationFilter extends GenericFilterBean {
    public TokenAuthorizationFilter(EnrollCashRepository enrollCashRepository) {
        this.enrollCashRepository = enrollCashRepository;
    }

    public EnrollCashRepository enrollCashRepository;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("before PITokenAuthorizationFilter");
        chain.doFilter(servletRequest, servletResponse);
        System.out.println("after PITokenAuthorizationFilter");
    }

    public EnrollCashRepository getEnrollCashRepository() {
        return enrollCashRepository;
    }

    public void setEnrollCashRepository(EnrollCashRepository enrollCashRepository) {
        this.enrollCashRepository = enrollCashRepository;
    }

}
Harshana
  • 7,297
  • 25
  • 99
  • 173

2 Answers2

15

Remove your FilterRegistrationBean and initialize TokenAuthorizationFilter inside your SecurityConfig like this:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public EnrollCashRepository enrollCashRepository;

    @Override
    public void configure(WebSecurity webSecurity) throws Exception
    {
        webSecurity.ignoring().antMatchers(HttpMethod.GET, "/health");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception 
    {
        http.addFilterBefore(tokenAuthorizationFilter(), BasicAuthenticationFilter.class);  
        http.authorizeRequests().antMatchers("/api/**").authenticated();    
    }

    private TokenAuthorizationFilter tokenAuthorizationFilter() 
    {
        return new TokenAuthorizationFilter(enrollCashRepository);
    }
}

Remove @Autowired and @Component annotation and set your EnrollCashRepository with constructor injection:

import org.springframework.web.filter.GenericFilterBean;

public class TokenAuthorizationFilter extends GenericFilterBean {

    private final EnrollCashRepository enrollCashRepository;

    public TokenAuthorizationFilter(EnrollCashRepository enrollCashRepository) 
    {
        this.enrollCashRepository = enrollCashRepository
    }
}
ksokol
  • 8,035
  • 3
  • 43
  • 56
  • Thanks. Now the enrollCashRepository is getting populate. But i get 403 - Forbidden error when i invoke the rest api. I edit the answer to show the rest controller. – Harshana Nov 05 '15 at 09:59
  • Could you please set log level to `DEBUG` on `org.springframework.security` and add the stacktrace to your question? – ksokol Nov 05 '15 at 10:06
  • it prints sys outs of filter i added, before PITokenAuthorizationFilter, after PITokenAuthorizationFilter. But above 403 error come from rest endpoint – Harshana Nov 05 '15 at 10:07
  • I believe you but DEBUG log shows the root cause of your 403. – ksokol Nov 05 '15 at 10:30
  • well i figure out what is the issue. Since i add spring-boot-starter-security in my pom, my whole application is protected via basic auth. Which i need to give a user name and a default security password. Do you know how can i disable this since i handle authentication and authorization separately by my self? – Harshana Nov 05 '15 at 14:31
  • i use below in my configaration class, but it doesnt disable the default authentication. @EnableAutoConfiguration(exclude = { org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class }) – Harshana Nov 05 '15 at 14:56
  • Maybe `@SpringBootApplication(exclude = SecurityAutoConfiguration.class)` may help you. Otherwise your configuration seems to be broken fundamentally. – ksokol Nov 05 '15 at 15:04
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/94393/discussion-between-ksokol-and-harshana). – ksokol Nov 06 '15 at 07:03
  • thanks. will do it. Above exclude you mentioned works perfectly which disable the default spring security config. 403 error comes from because of this, http.authorizeRequests().antMatchers("/api/**").authenticated();. But i need to match the request url also. Any thoughts please? – Harshana Nov 06 '15 at 07:52
  • Thanks, very clean. – jeremyjjbrown Nov 07 '18 at 01:46
0

I Added a Test Filter to my working class now and it worked fine. Here are the codes related to it.

Filter

@Component
public class TestFilter extends GenericFilterBean {

private static final Logger logger = LoggerFactory.getLogger(TestFilter.class);

@Autowired
UserService userService;

 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
     logger.error("=====================AWESOME=======================");
     chain.doFilter(request, response);
     userService.activate("123"); //this works
 }

}

App Security Config

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private TestFilter testFilter;

     @Override
     protected void configure(HttpSecurity http) throws Exception {
     //loginFailureHandler.setDefaultFailureUrl("/login?error=true");
     http.addFilterBefore(testFilter, BasicAuthenticationFilter.class);
     //Http other config here.
 }
}

App Config

@Configuration
@ImportResource({
    "classpath*:/context.xml"
})
@PropertySources(
    @PropertySource({
            "classpath:/application.yml"
    })
)
@Import({AppSecurityConfig.class, WebConfig.class,TestFilter.class})
public class AppConfig {
}
Maleen Abewardana
  • 13,600
  • 4
  • 36
  • 39