简体   繁体   中英

doFilter method called multiple times when an error is throw in a custom Servlet Filter

I have implemented a filter to check an IP adresses white list with Spring Security. It works, but if i throw an error in my doFilter method, the throw is called 3 times oO.

I found a solution with "return;", but i am not that happy with it. It means i have to log my error without using throw...

What do you think, is there any better way ? a best practice ?

@SpringBootApplication
public class DemoApplication {

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

Here is the web configuration

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                        .antMatchers("/**").permitAll().and()
                        .addFilterBefore(new CustomIpFilter(),
                                BasicAuthenticationFilter.class)
                        .csrf().disable()
                        .formLogin().disable();
        }
    }

Here is my filter

    @Log4j2
    @WebFilter
    public class CustomIpFilter implements Filter {

        Set<String> whitelist = new HashSet<>();

        public CustomIpFilter() {
            whitelist.add("0:0:0:0:0:0:0:1"); //localhost
            whitelist.add("127.0.0.1");
        }

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

            String ipAdress = request.getRemoteAddr();
            if (!whitelist.contains(ipAdress)) {
                log.error("Unknown IP adress");
                /* if the return is replaced by throw line, it still works, but doFilter will be called 3 times and throw 3 times the same error
                throw new UnknownHostException("Unknown IP adress");*/
                return;
            }
            chain.doFilter(request, response); //Continue
        }

        @Override
        public void destroy() {

        }

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {

        }
    }

The controller used to test

@RestController
@RequestMapping(value = "test")
public class LoggerController {

    @GetMapping("/go")
    public String logsTest() {
        System.out.println("ok");
        return "Ok";
    }
}

i have tried the same stuff with an interceptor removing Spring Security using "preHandle" method and i still have 3 times the Throw. So i start to understand why, look at the logs:

1st Throw

java.net.UnknownHostException: Unknown IP adress

2nd Throw

[nio-8181-exec-5] c.e.d.S.IpAdressInterceptor              : Unknown IP adress
[nio-8181-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] threw exception

3rd Throw:

[nio-8181-exec-5] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

Thanks for your help !

You are running in a Servlet environment. The servlet spec doesn't say you should respond to errors by throwing exceptions. Instead, you are supposed to respond with an HTTP status code and message. When you throw the exception the servlet container is going to do its best to figure out what to do but frequently that will result in a 500 Internal Server Error being returned to the user, which isn't accurate or helpful.

Just returning from the filter isn't correct either as you haven't put anything into the HTTP response. Again, you should be setting an appropriate status code in the response, such as 403 Forbidden, which gives the caller an indication that something isn't configured correctly.

To answer my question, here is finally my filter working properly as explained by @rgoers

@Log4j2
@WebFilter
public class CustomIpFilter implements Filter {

    private final Set<String> whitelist = new HashSet<>();
    private final String unauthorizedIpAddressMessage = "CONNECTION REFUSED: Unauthorized IP address: ";

    public CustomIpFilter() {
        whitelist.add("0:0:0:0:0:0:0:1"); //localhost
        whitelist.add("127.0.0.1");
    }

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

        String ipAddress = request.getRemoteAddr();

        if (!isAuthorizedIpAdress(ipAddress)) {
            log.error(unauthorizedIpAddressMessage + ipAddress);
            setUnauthorizedHttpServletResponse(response, unauthorizedIpAddressMessage + ipAddress);
            return;
        }

        chain.doFilter(request, response); //Continue
    }

    public void setUnauthorizedHttpServletResponse(ServletResponse response, String message)
            throws IOException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        httpResponse.getWriter().write(message);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    public boolean isAuthorizedIpAdress(String ipAddress) {
        if (Utils.isElementInSetList(whitelist, ipAddress)) {
            return true;
        }
        return false;
    }

    @Override
    public void destroy() {

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM