Метод doFilter вызывается несколько раз при возникновении ошибки в пользовательском фильтре сервлетов - PullRequest
0 голосов
/ 15 февраля 2020

Я реализовал фильтр для проверки белого списка IP-адресов с помощью Spring Security. Это работает, но если я выбрасываю ошибку в моем методе doFilter, бросок вызывается 3 раза oO.

Я нашел решение с "return;", но я не настолько доволен этим. Это значит, что я должен регистрировать свою ошибку без использования throw ...

Как вы думаете, есть ли лучший способ? лучшая практика?

@SpringBootApplication
public class DemoApplication {

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

Вот веб-конфигурация

    @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();
        }
    }

Вот мой фильтр

    @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 {

        }
    }

Контроллер, используемый для проверки

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

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

Я пробовал то же самое с перехватчиком, удаляющим Spring Security с использованием метода "preHandle", и у меня все еще есть 3 раза Throw. Итак, я начинаю понимать, почему, посмотрите на журналы:

1-й бросок

java.net.UnknownHostException: Unknown IP adress

2-й бросок

[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

3-й бросок:

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

Спасибо за помощь!

Ответы [ 2 ]

1 голос
/ 15 февраля 2020

Вы работаете в среде сервлета. Сервлет spe c не говорит, что вы должны реагировать на ошибки, создавая исключения. Вместо этого вы должны ответить с кодом состояния HTTP и сообщением. Когда вы генерируете исключение, контейнер сервлетов будет делать все возможное, чтобы выяснить, что делать, но часто это приведет к тому, что 500 Internal Server Error будет возвращено пользователю, что не является точным или бесполезным.

Просто возврат из фильтра также не корректен, так как вы ничего не добавили в HTTP-ответ. Опять же, вы должны установить соответствующий код состояния в ответе, например, 403 Запрещено, что дает вызывающему абоненту указание, что что-то настроено неправильно.

0 голосов
/ 16 февраля 2020

Чтобы ответить на мой вопрос, вот наконец мой фильтр работает правильно, как объяснено @ 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 {

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...