簡體   English   中英

在自定義 Servlet 過濾器中拋出錯誤時多次調用 doFilter 方法

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

我已經實現了一個過濾器來使用 Spring Security 檢查 IP 地址白名單。 它有效,但是如果我在 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";
    }
}

我已經嘗試過使用“preHandle”方法使用攔截器刪除 Spring Security 的相同內容,但我仍然有 3 次投擲。 所以我開始明白為什么,看看日志:

第一次投擲

java.net.UnknownHostException: Unknown IP adress

第二次投擲

[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]

謝謝你的幫助 !

您正在 Servlet 環境中運行。 servlet 規范沒有說你應該通過拋出異常來響應錯誤。 相反,您應該使用 HTTP 狀態代碼和消息進行響應。 當您拋出異常時,servlet 容器將盡力找出要做什么,但經常會導致 500 Internal Server Error 返回給用戶,這是不准確或有幫助的。

僅僅從過濾器返回也不正確,因為您沒有在 HTTP 響應中放入任何內容。 同樣,您應該在響應中設置適當的狀態代碼,例如 403 Forbidden,它向調用者指示某些內容未正確配置。

為了回答我的問題,我的過濾器終於按照@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 {

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM