How can I add a filter class in Spring Boot?
Asked Answered
W

29

288

Is there any annotation for a Filter class (for web applications) in Spring Boot? Perhaps @Filter?

I want to add a custom filter in my project.

The Spring Boot Reference Guide mentioned about FilterRegistrationBean, but I am not sure how to use it.

Won answered 7/11, 2013 at 0:52 Comment(3)
can you tell me you exact requirement. If you want filter classes for ComponentScan then there is an annotation for that "@ComponentScan.Filter"Patently
you should write more detail, we have different type of filter, ex: filter for requests , client side filter to filter from a list and so onOxytocic
The first comment from @Irxw is not correct: Servlet Filters annotated with \\@WebFilter are actually registered as a real servlet filter. This means that it acts before servlet execution and according to the servlet specifications!Graphology
A
188

If you want to setup a third-party filter you can use FilterRegistrationBean.

For example, the equivalent of web.xml:

<filter>
     <filter-name>SomeFilter</filter-name>
        <filter-class>com.somecompany.SomeFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SomeFilter</filter-name>
    <url-pattern>/url/*</url-pattern>
    <init-param>
        <param-name>paramName</param-name>
        <param-value>paramValue</param-value>
    </init-param>
</filter-mapping>

These will be the two beans in your @Configuration file:

@Bean
public FilterRegistrationBean someFilterRegistration() {

    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(someFilter());
    registration.addUrlPatterns("/url/*");
    registration.addInitParameter("paramName", "paramValue");
    registration.setName("someFilter");
    registration.setOrder(1);
    return registration;
}

public Filter someFilter() {
    return new SomeFilter();
}

The above was tested with Spring Boot 1.2.3.

Anatollo answered 5/6, 2015 at 5:9 Comment(13)
what if i want to add multiple filters? @OpalUncloak
Just add an additional @Bean public FilterRegistrationBean additionalFilterRegistration()Anatollo
How does one know the order in which the filters are applied?Murphree
FilterRegistrationBean.setOrderAnatollo
You don't need filter bean when you call the method someFilter() directly.Sprite
The sample misses @Bean onto someFilter().Harper
@HaimRaman HI! do you have any solution for his issue : #53775409 . any help will be appreciated.Josiah
@Haim Need some help over here https://mcmap.net/q/109832/-redirect-to-a-different-host-in-spring-boot-non-www-to-www-url/7538821Perl
What about WebMvcConfigurer?Shriver
You can't use WebMvcConfigurer to configure servlet filters. see #33464418Anatollo
What package is Filter in? I'm seeing over 24 possible matches. Maybe include an import statement snippet.Diabetic
how doe i add the FilterRegistrationBean to the web security? Does it automaticly looks for beans of FilterRegistrationBean ?Leprosy
I suggest that you add this on a question of it's ownAnatollo
G
132

Here is an example of one method of including a custom filter in a Spring Boot MVC application. Be sure to include the package in a component scan:

package com.dearheart.gtsc.filters;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
public class XClacksOverhead implements Filter {

  public static final String X_CLACKS_OVERHEAD = "X-Clacks-Overhead";

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

    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader(X_CLACKS_OVERHEAD, "GNU Terry Pratchett");
    chain.doFilter(req, res);
  }

  @Override
  public void destroy() {}

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

}
Goldstone answered 22/3, 2015 at 18:18 Comment(6)
Should filter be registered somewhere?Aforethought
When I tried that approach, Filter was created as bean and even was injected to other class but init() method didn't run. Probably, init() works only in 'normal' registering not by spring container. I think, one may use PostConstruct instead of init() but I didn't try that as I refused declaring Filter as Spring bean.Walston
What about filter ordering using this approach?Harper
How can we get RS body from ServletResponse?Illyricum
One important thing to note is that the name of your bean (based on your class name) should not be the same as a Spring bean. For instance, you might be tempted to create a MetricsFilter, but this bean will be overshadowed by the Spring actuator bean of the same name. Learned this the hard way...Fang
Perhaps better to extend org.springframework.web.filter.GenericFilterBean?Placeman
S
97

There are three ways to add your filter,

  1. Annotate your filter with one of the Spring stereotypes such as @Component
  2. Register a @Bean with Filter type in Spring @Configuration
  3. Register a @Bean with FilterRegistrationBean type in Spring @Configuration

Either #1 or #2 will do if you want your filter applies to all requests without customization, use #3 otherwise. You don't need to specify component scan for #1 to work as long as you place your filter class in the same or sub-package of your SpringApplication class. For #3, use along with #2 is only necessary when you want Spring to manage your filter class such as have it auto wired dependencies. It works just fine for me to new my filter which doesn't need any dependency autowiring/injection.

Although combining #2 and #3 works fine, I was surprised it doesn't end up with two filters applying twice. My guess is that Spring combines the two beans as one when it calls the same method to create both of them. In case you want to use #3 alone with authowiring, you can AutowireCapableBeanFactory. The following is an example,

private @Autowired AutowireCapableBeanFactory beanFactory;

    @Bean
    public FilterRegistrationBean myFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        Filter myFilter = new MyFilter();
        beanFactory.autowireBean(myFilter);
        registration.setFilter(myFilter);
        registration.addUrlPatterns("/myfilterpath/*");
        return registration;
    }
Silkstocking answered 16/12, 2015 at 1:24 Comment(2)
Excellent answer. Thanks for detailing all the options and also covering how to autowire your Filter while using FilterRegistrationBeanAfghani
This is also described here: baeldung.com/spring-boot-add-filterPlaceman
T
85

There isn't a special annotation to denote a servlet filter. You just declare a @Bean of type Filter (or FilterRegistrationBean). An example (adding a custom header to all responses) is in Boot's own EndpointWebMvcAutoConfiguration;

If you only declare a Filter it will be applied to all requests. If you also add a FilterRegistrationBean you can additionally specify individual servlets and url patterns to apply.

Note:

As of Spring Boot 1.4, FilterRegistrationBean is not deprecated and simply moved packages from org.springframework.boot.context.embedded.FilterRegistrationBean to org.springframework.boot.web.servlet.FilterRegistrationBean

Thrice answered 7/11, 2013 at 8:17 Comment(5)
Would you mind to tell me how to include corresponding entry in build.gradle? I added the following, but it doesn't get compiled: providedCompile('javax.servlet:servlet-api:2.5') runtime('javax.servlet:jstl:1.1.2')Won
Spring Boot isn't going to work with Servlet 2.5, and there isn't really much support for JSP yet. I'm not really a gradler, so I don't know what you are trying to do. What's wrong with "compile"? Does it work if you just depend on "spring-boot-starter-web"? (I don't think these questions are related to the original question though, so maybe you should post again with the new questions?)Thrice
I added a filter by implementing Filter interface, however Eclipse is unable to find the interface. So I am trying to figure out how to add it to classpath for compiling.Won
Yes, of course you need to have Filter on your classpath. Normally I would just use the spring-boot-starter-web to pull in all the relevant depdendencies (e.g. here).Thrice
As other responses detail, you can also just annotate your Filter class with @Component and it will be automatically registered (for all URLs).Placeman
C
45

UPDATE: 2022-05-29:

There are two simple ways to do this in Spring Boot 1.5.8.RELEASE and there isn't any need for XML.

First way:

If you do not have any specific URL pattern, you can use @Component like this (full code and details are here https://github.com/surasint/surasint-examples/tree/master/spring-boot-jdbi/3_spring-boot-filter , look at README.txt to start):

@Component
public class ExampleFilter implements Filter {
    ...
}

Second way:

If you want to use URL patterns, you can use @WebFilter like this (full code and details are here https://github.com/surasint/surasint-examples/tree/master/spring-boot-jdbi/4_spring-boot-filter-urlpattern , look at README.txt to start):

@WebFilter(urlPatterns = "/api/count")
public class ExampleFilter implements Filter {
    ...
}

But you also need to add @ServletComponentScan annotation in your @SpringBootApplication class:

@ServletComponentScan
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
    ...
}

Note that @Component is Spring's annotation, but @WebFilter is not. @WebFilter is Servlet 3 annotation.

Both ways, you just need a basic Spring Boot dependency in pom.xml (there isn't any need for an explicit Tomcat embedded jasper)

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
    </parent>

    <groupId>com.surasint.example</groupId>
    <artifactId>spring-boot-04</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

WARNING: The first way, if the Controller in Spring Boot returns to a JSP file, the request will pass the filter twice.

While, in the second way, the request will pass the filter only once.

I prefer the second way, because it is more similar to default behavior in the Servlet specification.

Convey answered 16/12, 2017 at 13:10 Comment(6)
I've seen Filter interface getting called numerous times during the launch of the applicationContext. Is there any way to execute it only once ?Raybin
@PAA you mean from my examples ?Convey
@Surasin : Great articles on your blog. Question - Instead of \@ServletComponentScan, won't mentioning \@ComponentScan on the filter class along with \@WebFilter be enough for Spring App context to pick it up?Horror
All the www.surasint.com links are broken ("Hmm. We’re having trouble finding that site. We can’t connect to the server at www.surasint.com.").Greatnephew
@PeterMortensen it is gone. Gcloud has completely destroyed it. And I don't have backup anywhere T-TConvey
You can use \@Component on the filter instead of using \@ServletComponentScan on the App classFotheringhay
A
26

Here is an example of my custom Filter class:

package com.dawson.controller.filter;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class DawsonApiFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        if (req.getHeader("x-dawson-nonce") == null || req.getHeader("x-dawson-signature") == null) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setContentType("application/json");
            httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Required headers not specified in the request");
            return;
        }
        chain.doFilter(request, response);
    }
}

And I added it to the Spring Boot configuration by adding it to Configuration class as follows:

package com.dawson.configuration;

import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.dawson.controller.filter.DawsonApiFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@SpringBootApplication
public class ApplicationConfiguration {
    @Bean
    public FilterRegistrationBean dawsonApiFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new DawsonApiFilter());

        // In case you want the filter to apply to specific URL patterns only
        registration.addUrlPatterns("/dawson/*");
        return registration;
    }
}
Asafoetida answered 2/5, 2017 at 17:47 Comment(0)
L
18

From the Spring documentation,

Embedded servlet containers - Add a Servlet, Filter or Listener to an application

To add a Servlet, Filter, or Servlet *Listener provide a @Bean definition for it.

For example:

@Bean
public Filter compressFilter() {
    CompressingFilter compressFilter = new CompressingFilter();
    return compressFilter;
}

Add this @Bean configuration to your @Configuration class and the filter will be registered on startup.

Also you can add Servlets, Filters, and Listeners using classpath scanning,

@WebServlet, @WebFilter, and @WebListener annotated classes can be automatically registered with an embedded servlet container by annotating a @Configuration class with @ServletComponentScan and specifying the package(s) containing the components that you want to register. By default, @ServletComponentScan will scan from the package of the annotated class.

Limner answered 8/8, 2016 at 13:37 Comment(2)
docs.spring.io/spring-boot/docs/current/reference/html/… didn't work for me but docs.spring.io/spring-boot/docs/1.5.8.RELEASE/reference/html/… worked for me.Nib
The link is broken (404).Greatnephew
M
15

We have roughly four different options to register a filter using Spring.

Firstly, we can create a Spring bean implementing Filter or extending HttpFilter:

@Component
public class MyFilter extends HttpFilter {

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        // Implementation details...

        chain.doFilter(request, response);
    }
}

Secondly, we can create a Spring bean extending GenericFilterBean:

@Component
public class MyFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
  throws IOException, ServletException {
    //Implementation details...

        chain.doFilter(currentRequest, servletResponse);
    }
}

Alternatively we can use the FilterRegistrationBean class:

@Configuration
public class FilterConfiguration {

    private final MyFilter myFilter;

    @Autowired
    public FilterConfiguration(MyFilter myFilter) {
        this.myFilter = myFilter;
    }

    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistration() {
        FilterRegistrationBean<DateLoggingFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(myFilter);
        filterRegistrationBean.setUrlPatterns(Collections.singletonList("/*"));
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST);
        filterRegistrationBean.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
        return filterRegistrationBean;
    }
}

And lastly we can use the @WebFilter annotation with @ServletComponentScan:

@WebFilter(urlPatterns = "/*", dispatcherTypes = {DispatcherType.REQUEST})
public class MyFilter extends HttpFilter {

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  throws IOException, ServletException {
        // Implementation details...

        chain.doFilter(request, response);
    }
}
Myrtia answered 27/7, 2019 at 7:46 Comment(1)
Which filter to use and why ?Raybin
U
10

If you use Spring Boot + Spring Security, you can do that in the security configuration.

In the below example, I'm adding a custom filter before the UsernamePasswordAuthenticationFilter (see all the default Spring Security filters and their order).

@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired FilterDependency filterDependency;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(
                new MyFilter(filterDependency),
                UsernamePasswordAuthenticationFilter.class);
    }
}

And the filter class

class MyFilter extends OncePerRequestFilter  {
    private final FilterDependency filterDependency;

    public MyFilter(FilterDependency filterDependency) {
        this.filterDependency = filterDependency;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response,
        FilterChain filterChain)
        throws ServletException, IOException {

        // Filter
        filterChain.doFilter(request, response);
    }
}
Unclasp answered 6/7, 2017 at 10:40 Comment(0)
M
9

Using the @WebFilter annotation, it can be done as follows:

@WebFilter(urlPatterns = {"/*" })
public class AuthenticationFilter implements Filter{

    private static Logger logger = Logger.getLogger(AuthenticationFilter.class);

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

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

         logger.info("checking client id in filter");
        HttpServletRequest request = (HttpServletRequest) arg0;
        String clientId = request.getHeader("clientId");
        if (StringUtils.isNotEmpty(clientId)) {
            chain.doFilter(request, response);
        } else {
            logger.error("client id missing.");
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }

}
Memnon answered 23/8, 2017 at 7:31 Comment(1)
Also add @ServletComponentScanHurling
A
5

This filter will also help you to allow cross origin access

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {

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

            HttpServletResponse response = (HttpServletResponse) res;
            HttpServletRequest request = (HttpServletRequest) req;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            response.setHeader("Access-Control-Max-Age", "20000");
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");

            if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
                response.setStatus(HttpServletResponse.SC_OK);
            } else {
                chain.doFilter(req, res);
            }
    }


    public void destroy() {}

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }

}
Apparel answered 24/7, 2019 at 12:50 Comment(0)
B
5

Step 1: Create a filter component by implementing the Filter interface.

@Component
public class PerformanceFilter implements Filter {

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

        ...
        ...
    }

}

Step 2: Set this filter to the URI patterns using FilterRegistrationBean.

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<PerformanceFilter> perfFilter() {
        FilterRegistrationBean<PerformanceFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new PerformanceFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }
}

You can refer to this link for a complete application.

Buchalter answered 10/1, 2020 at 5:20 Comment(1)
Straightforward answer but using springboot the second step is not needed at least you want to add the filter for a specific patter. Visit baeldung.com/spring-boot-add-filter for similar brief example.Turbulent
H
4

It's more an advice than an answer, but if you are using a Spring MVC in your web application the good idea is to use Spring HandlerInterceptor instead of Filter.

It can do the same job, but also

  • Can work with ModelAndView
  • Its methods can be called before and after request processing, or after request completion.
  • It can be easily tested

1. Implement HandlerInterceptor interface and add a @Component annotation to your class

@Component
public class SecurityInterceptor implements HandlerInterceptor {

    private static Logger log = LoggerFactory.getLogger(SecurityInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.getSession(true);
        if(isLoggedIn(request))
            return true;

        response.getWriter().write("{\"loggedIn\":false}");
        return false;
    }

    private boolean isLoggedIn(HttpServletRequest request) {
        try {
            UserSession userSession = (UserSession) request.getSession(true).getAttribute("userSession");
            return userSession != null && userSession.isLoggedIn();
        } catch(IllegalStateException ex) {
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {

    }
}

2. Configure your Interceptor

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private HandlerInterceptor securityInterceptor;

    @Autowired
    public void setSecurityInterceptor(HandlerInterceptor securityInterceptor) {
        this.securityInterceptor = securityInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(securityInterceptor).addPathPatterns("/**").excludePathPatterns("/login", "/logout");
    }

}
Hatchett answered 2/4, 2018 at 11:43 Comment(1)
Simple and elegant! ThanksBramante
B
4

You need two main things:

  • Add @ServletComponentScan to your Main Class

  • You may add a package named filter inside it. You create a Filter class that has the following:

      @Component
      @Order(Ordered.HIGHEST_PRECEDENCE)
      public class RequestFilter implements Filter {
    
          // whatever field you have
    
          public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
              HttpServletResponse response = (HttpServletResponse) res;
              HttpServletRequest request = (HttpServletRequest) req;
    
              // Whatever implementation you want
    
              try {
                  chain.doFilter(req, res);
              } catch(Exception e) {
                  e.printStackTrace();
              }
          }
    
          public void init(FilterConfig filterConfig) {
          }
    
          public void destroy() {
          }
      }
    
Barger answered 20/8, 2019 at 22:29 Comment(0)
S
3

You can use @WebFilter javax.servlet.annotation.WebFilter on a class that implements javax.servlet.Filter:

@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
}

Then use @ServletComponentScan to register.

Sustain answered 18/7, 2017 at 10:41 Comment(0)
A
3

I saw a lot of answers here, but I didn't try any of them. I've just created the filter as in the following code.

import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/Admin")
@Configuration
public class AdminFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse  servletResponse, FilterChain filterChain) throws IOException, ServletException      {
    System.out.println("happened");

    }

    @Override
    public void destroy() {

    }
}

And I left the remaining Spring Boot application as it was.

Alignment answered 26/2, 2018 at 19:15 Comment(0)
S
2

Use:

@WebFilter(urlPatterns="/*")
public class XSSFilter implements Filter {

    private static final org.apache.log4j.Logger LOGGER = LogManager.getLogger(XSSFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("Initiating XSSFilter... ");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpRequestWrapper requestWrapper = new HttpRequestWrapper(req);
        chain.doFilter(requestWrapper, response);
    }

    @Override
    public void destroy() {
        LOGGER.info("Destroying XSSFilter... ");
    }

}

You need to implement Filter, and it needs to be annotated with @WebFilter(urlPatterns="/*").

And in the Application or Configuration classes, you need to add @ServletComponentScan. By this, your filter will get registered.

Sky answered 6/6, 2018 at 11:31 Comment(1)
This @WebFilter is only since Servlet 3.0. So it might not work properly for 2.5Hoopen
R
1

You can also make a filter by using @WebFilter and implementing Filter. It will do.

@Configuration
public class AppInConfig
{
    @Bean
    @Order(1)
    public FilterRegistrationBean aiFilterRegistration()
    {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new TrackingFilter());
        registration.addUrlPatterns("/**");
        registration.setOrder(1);
        return registration;
    }

    @Bean(name = "TrackingFilter")
    public Filter TrackingFilter()
    {
        return new TrackingFilter();
    }
}
Riordan answered 5/1, 2018 at 9:7 Comment(0)
P
1

I saw the answer by Vasily Komarov. Here is a similar approach, but using abstract HandlerInterceptorAdapter class instead of using HandlerInterceptor.

Here is an example...

@Component
public class CustomInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    }
}

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private CustomInterceptor customInterceptor ;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(customInterceptor );
    }

}
Prophesy answered 13/6, 2018 at 5:55 Comment(0)
B
1

Filters, as the name suggest, used to perform filtering on either the request to a resource or on the response from a resource, or both. Spring Boot provides a few options to register custom filters in the Spring Boot application. Let’s look at the different options.

1. Define Spring Boot filter and invocation order

Implement the Filter interface to create a new filter in Spring Boot.

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("########## Initiating Custom filter ##########");
    }

    @Override
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse,
                         FilterChain filterChain)
                         throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        LOGGER.info("Logging Request  {} : {}", request.getMethod(), request.getRequestURI());

        // Call next filter in the filter chain
        filterChain.doFilter(request, response);

        LOGGER.info("Logging Response :{}", response.getContentType());
    }

    @Override
    public void destroy() {
        // TODO: 7/4/2018
    }
}

Let’s quickly look at some important points in the above code

  • The filter registered by the @Component annotation.

  • To fire filters in the right order, we needed to use the @Order annotation.

     @Component
     @Order(1)
     public class CustomFirstFilter implements Filter {
    
     }
    
     @Component
     @Order(2)
     public class CustomSecondFilter implements Filter {
    
     }
    

In the above code, CustomFirstFilter will run before the CustomSecondFilter.

The lower the number, the higher the precedence

2. URL Pattern

If the convention-based mapping is not flexible enough, we can use FilterRegistrationBean for the complete control of the application. Here, don’t use @Component annotation for the filter class but register the filter using a FilterRegistrationBean.

public class CustomURLFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomURLFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("########## Initiating CustomURLFilter filter ##########");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        LOGGER.info("This Filter is only called when request is mapped for /customer resource");

        // Call the next filter in the filter chain
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

Register the custom Filter using FilterRegistrationBean.

@Configuration
public class AppConfig {

    @Bean
    public FilterRegistrationBean < CustomURLFilter > filterRegistrationBean() {
        FilterRegistrationBean < CustomURLFilter > registrationBean = new FilterRegistrationBean();
        CustomURLFilter customURLFilter = new CustomURLFilter();

        registrationBean.setFilter(customURLFilter);
        registrationBean.addUrlPatterns("/greeting/*");
        registrationBean.setOrder(2); // Set precedence
        return registrationBean;
    }
}
Bifocals answered 29/5, 2019 at 11:9 Comment(0)
E
0

First, add @ServletComponentScan to your SpringBootApplication class.

@ServletComponentScan
public class Application {

Second, create a filter file extending Filter or third-party filter class and add @WebFilter to this file like this:

@Order(1) //optional
@WebFilter(filterName = "XXXFilter", urlPatterns = "/*",
    dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD},
    initParams = {@WebInitParam(name = "confPath", value = "classpath:/xxx.xml")})
public class XXXFilter extends Filter{
Ebb answered 6/2, 2018 at 5:54 Comment(0)
E
0

As you all know, Spring Boot is a wonderful way of developing a web application or stand-alone application with minimum configuration and opinionated setup.

This is how I have achieved a web filter development in a Spring Boot application

My SpringBootApp specifications:

Spring Boot version: 2.0.4.RELEASE
Java version: 8.0
Servlet specification: Servlet 3.0 (Mandatory and Important)

I declared my web filter in the following manner, adhering to the Servlet specification 3.0

Enter image description here

This is the programmatic way of defining a filter as a replacement to web.xml-based definitions.

The "@Webfilter" annotation will be processed by the container during deployment. The Filter class, in which it is found, will be created as per the configuration and applied to the URL patterns, javax.servlet.Servlets and javax.servlet.DispatcherTypes.

To avoid Web.xml completely and to achieve "Deployable" WebApp:

To deploy a Spring Boot application as "Traditional WAR", the application class should extend SpringBootServletInitializer.

NOTE:

SpringBootServletInitializer is a "programmatic implementation" of web.xml with reference to the Servlet 3.0+ specifications, which requires an implementation of WebApplicationInitializer.

Thus, SpringBootApplication doesn't require "web.xml" as its application class (after extending SpringBootServletInitializer). It scans for

  • @WebFilter,
  • @WebListener and
  • @WebServlet.

Annotation @ServletComponentScan

This annotation enables scanning base packages for the web components annotated with @WebFilter, @WebListener and @WebServlet.

Due to the fact that embedded containers do not support @WebServlet, @WebFilter and @WebListener annotations, Spring Boot, relying greatly on embedded containers, introduced this new annotation @ServletComponentScan to support some dependent JAR files that use these three annotations.

Scanning is only performed when using an embedded Servlet container.

The following is my Spring Boot application class definition:

Enter image description here

Custom Servlet Initializer:

Here: I have defined a custom class: "ServletInitializer" which extends Class: SpringBootServletInitializer.

As explained earlier, SpringBootServletInitializer is responsible for scanning annotations:

  • @WebFilter,
  • @WebListener and
  • @WebServlet.

And hence the Spring Boot application class should

  • Either extend the class: SpringBootServletInitializer or
  • extend the custom class which extends the class: SpringBootServletInitializer

Enter image description here

Engraving answered 7/4, 2019 at 10:22 Comment(0)
I
0

For Spring Boot in any configuration class I've done:

@Bean
public OncePerRequestFilter myFilter() {
    return new OncePerRequestFilter() {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            AuthUser authUser = SecurityUtil.safeGet(); // applied after secutiry filters
            ...
            filterChain.doFilter(request, response);
        }
    };
}

That's all, no any registration needed. See also What is OncePerRequestFilter?

Impresario answered 9/10, 2021 at 11:8 Comment(0)
A
0

Annotate your filter with one of the Spring stereotypes such as @Component. Register a @Bean with Filter type in Spring @Configuration. Register a @Bean with FilterRegistrationBean type in Spring @Configuration.

Archangel answered 12/9, 2022 at 11:51 Comment(0)
A
0

For filtering based on any criteria and for any list in spring boot, query language is more flexible and allows us to filter down to exactly the resources we need. For instance, if we have simple entity like User and define it like this.

@Entity
public class User {
@Id
@GeneratedValue(strategy = 
GenerationType.AUTO)
private Long id;

private String firstName;
private String lastName;
private String email;

private int age;

//Setter and getter as usual

Then we create a UserSpecification that implements the Specification interface, and we're going to pass in our own constraint to construct the actual query. In this part methods related to criteria and builder as defined are very useful and flexible.

public class UserSpecification implements Specification<User> {

private SearchCriteria criteria;

@Override
public Predicate toPredicate
  (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

    if (criteria.getOperation().equalsIgnoreCase(">")) {
        return builder.greaterThanOrEqualTo(
          root.<String> get(criteria.getKey()), criteria.getValue().toString());
    } 
    else if (criteria.getOperation().equalsIgnoreCase("<")) {
        return builder.lessThanOrEqualTo(
          root.<String> get(criteria.getKey()), criteria.getValue().toString());
    } 
    else if (criteria.getOperation().equalsIgnoreCase(":")) {
        if (root.get(criteria.getKey()).getJavaType() == String.class) {
            return builder.like(
              root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
        } else {
            return builder.equal(root.get(criteria.getKey()), criteria.getValue());
        }
    }
    return null;
}
}

And beside we create a Specification based on some simple constraints that represented in the following SearchCriteria class, any criteria can be create like this:

public class SearchCriteria {
private String key;
private String operation;
private Object value;
 }

At the end define UserRepository and extend JpaSpecificationExecutor,

public interface UserRepository 
extends JpaRepository<User, Long>, 
JpaSpecificationExecutor<User> {}
Ardyth answered 5/1, 2023 at 19:30 Comment(0)
B
0

Here is pretty simple way of defining Filter:

@Component
@Order(1)
public class SampleFilter implements Filter {


    @PostConstruct
    public void init() {

        System.out.println("Sample Filter initialized");

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // with Spring Dependency Injection this method will not be invoked
    }

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

    

        chain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}
Bellebelleek answered 6/4, 2023 at 9:39 Comment(0)
B
0

Here is a simple Example how to use FilterRegistrationBean:

import javax.servlet.*;
import java.io.IOException;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MySpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }

    @Bean
    public FilterRegistrationBean<MyCustomFilter> myCustomFilterRegistrationBean() {
        FilterRegistrationBean<MyCustomFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyCustomFilter());
        registrationBean.addUrlPatterns("/*"); /
        return registrationBean;
    }

    public static class MyCustomFilter implements Filter {

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            // Your filter logic comes here
        
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
}

Here are some useful resources:

Bolero answered 6/4, 2023 at 9:50 Comment(0)
L
0

Short answer to your question:

@Component
class MyCustomFilter : OncePerRequestFilter() {
    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        //some work: adding headers, working with authentication or something else
        filterChain.doFilter(request, response)
    }
}

More details below:

Let's say we have the following chain:

@Bean
@Throws(Exception::class)
fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http.authorizeRequests()
        .antMatchers(HttpMethod.POST, "/first", "/second")
        .authenticated()
        .anyRequest()
        .permitAll()
        .and()
        .httpBasic()
        .authenticationEntryPoint(auditAuthenticationEntryPoint)
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and().formLogin().disable()
        .csrf().disable()
        .cors().configurationSource(corsConfigurationSource())
    return http.build()
}

And we want to add the following filter to this chain between some specific filters.

Here are a few ways to add our filter to the chain:

1) adding the @Order annotation to the filter:

@Component
@Order(5)
class MyCustomFilter : OncePerRequestFilter()

Note that:

  • If you do not specify an order in the annotation, then the default order is: Ordered.LOWEST_PRECEDENCE - your filter will be the last one in the chain.
  • If you are working with Authentication in your filter (through authentication providers) then Ordered.LOWEST_PRECEDENCE and Ordered.HIGHEST_PRECEDENCE not suitable for your case because:
    • in case Ordered.HIGHEST_PRECEDENCE filterSecurityContextPersistenceFilter which will be executed after your filter will clear the SecurityContext even if your filter added an Authentication object to the SecurityContext
    • in the case of Ordered.LOWEST_PRECEDENCE your filter will not be called at all: AnonymousAuthenticationFilter will set the Authentication object to Anonymous and you will receive a 401 or 403 response before the chain calls your filter
    • In this case, you need to get the chain and determine the specific order of your filter via the FilterChainProxy and the doFilter(ServletRequest request, ServletResponse response) method, getting this.additionalFilters. For example, 5. But this is not the best way to determine the order

2) The standard (and best) way is through setting up the filter chain itself:

    @Bean
    @Throws(Exception::class)
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http.authorizeRequests()
            ...
            .addFilterBefore(MyCustomFulter(), BasicAuthenticationFilter::class.java)
            ...
        return http.build()
    }

3) Injecting a filter into a chain in @PostConstruct

In my case, .addFilterBefore() was not possible due to the fact that the filter was added from the starter. My starter needs to add a filter to each chain after the LogoutFilter. Since there can be multiple chains in a context, I add a filter to each one. Thus, when adding my starter to the application , the filter is added to the required place without any additional configuration:

@Configuration
@ComponentScan
@ConfigurationPropertiesScan
class CommonConfig {
    @Autowired
    lateinit var chains: List<SecurityFilterChain>

    @Autowired
    lateinit var myCustomFilter: MyCustomFilter

    @PostConstruct
    fun post() {
        chains.forEach {
            for (i in it.filters.indices){
                if (it.filters[i] is LogoutFilter) {
                    it.filters.add(i + 1, myCustomFilter)
                }
            }
        }
    }
}
Lauber answered 22/4, 2023 at 14:10 Comment(0)
C
-5

Filters are mostly used in logger files. It varies according to the logger you using in the project.

Let me explain for log4j2:

<Filters>
    <!-- It prevents an error -->
    <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>

    <!-- It prevents debug -->
    <ThresholdFilter level="debug" onMatch="DENY" onMismatch="NEUTRAL" />

    <!-- It allows all levels except debug/trace -->
    <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>

Filters are used to restrict the data and I used the threshold filter further to restrict the levels of data in the flow. I mentioned the levels that can be restricted over there.

For your further reference, see the level order of log4j2 - Log4J Levels: ALL > TRACE > DEBUG > INFO > WARN > ERROR > FATAL > OFF

Centum answered 10/11, 2017 at 13:3 Comment(1)
FilterRegistrationBean as mentioned in the question is for javax.servlet.Filter, this answer talks about org.apache.logging.log4j.core.FilterShrader

© 2022 - 2024 — McMap. All rights reserved.