15

I am currently working on a Spring project and I am making a new filter that checks if a valid JWT has been sent in the request.

I am running into an issue where I can't get a value from my application.yml file using the @Value annotation like so.

@Component
@Order(2)
public class JwtConfiguration implements Filter {

    @Value("${jwt.secret}")
    private String jwtSecret;

I know this works fine because I have the same thing in my unit test.

I have read somewhere that the filter is not in the application context so it will not have access to configuration and I will not be able to autowire dependencies.

Does anyone know a good technique for getting values from my application.yml to my filter?

I am also not using any XML configuration and would prefer a solution that doesn't use them.

I am using Spring Boot version 1.3.3.

David Jones
  • 4,275
  • 6
  • 27
  • 51

3 Answers3

5

This can be achieved by implementing ServletContextInitializer. See below sample code.

@Configuration
public class WebConfigurer implements ServletContextInitializer {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
        initFilter(servletContext, disps);
    }


    private void initFilter(ServletContext servletContext,
                                              EnumSet<DispatcherType> disps) {
        FilterRegistration.Dynamic myFilter =
            servletContext.addFilter("myFilter",
                new MyFilterClass(jwtSecret));

        // You can pass null as first parameter to below API calls
        myFilter.addMappingForUrlPatterns(disps, true, "/content/*");
        myFilter.addMappingForUrlPatterns(disps, true, "/app/*");
        myFilter.setAsyncSupported(true);
    }

}

Edit/Update:

I suppose there is another way to add filters using Java Config

You can use FilterRegistrationBean to register the filters. Here you can set the order using setOrder method. But think it will create as many ServletContextInitializer as there are filters because FilterRegistrationBean is a ServletContextInitializer See

Community
  • 1
  • 1
Sangram Jadhav
  • 2,438
  • 16
  • 17
  • Hi thank you for the answer, I used your code and tweaked it a bit and now all my tests pass! I have a question about the @Order annotation. Will this still be honoured using this configurer? And will my other filters be affected? – David Jones Jun 08 '16 at 09:27
  • I think the @Order annotation is not useful here as we are adding filter directly to servlet context. Also I assume that servlet context will honor insertion order. Thats what happens if you declare filters in web.xml. So if you want particular order, add all the filters in above code one by one – Sangram Jadhav Jun 08 '16 at 09:39
  • Thanks for the feedback. I have used this to add all my filters and they execute in the correct order. Everything now seems to be working on my end. – David Jones Jun 08 '16 at 14:47
0

org.springframework.web.filter.DelegatingFilterProxy

liaozq
  • 140
  • 1
  • 4
  • 5
    while this is the right technique, this is not an appropriate answer. Please elaborate. As it is, I don't know whether to upvote or flag this answer – Sean Patrick Floyd Jun 08 '16 at 09:13
  • I found instructions on how to use the DelegatingFilterProxy here https://www.deadcoderising.com/2015-05-04-dependency-injection-into-filters-using-delegatingfilterproxy/ – Samantha Catania Jul 11 '19 at 09:31
0

I will describe the way to do it in Spring boot using DelegatingFilterProxy:

1) add to your application.java this bean:

@Bean
public FilterRegistrationBean securityFilterChainRegistration() {
    DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
    delegatingFilterProxy.setTargetBeanName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
    FilterRegistrationBean registrationBean = new FilterRegistrationBean(delegatingFilterProxy);
    registrationBean.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
}

2) create your filterbean:

@Component(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public class TokenFilter extends GenericFilterBean {
@Value("${path.to.client.id}") String clientId;

@Autowired
RequestDumperFilter requestDumperFilter;

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

    // do stuff.
}}

This is basically it. Now you can play around with your favorite way of protecting resources. For example, I added @EnableGlobalMethodSecurity(prePostEnabled = true) annotation to my application class, and protected resources with things like @PreAuthorize("hasRole('ROLE_USER')").

khaidar
  • 21
  • 4