【问题标题】:How to forcefully end filter-chain in an early servlet/spring boot filter如何在早期的 servlet/spring boot 过滤器中强制结束过滤器链
【发布时间】:2021-09-09 17:56:31
【问题描述】:

拥有多租户应用程序,我想尽早结束没有租户的任何请求。

设置/场景

我使用 spring session 和 spring security 运行 spring boot (web)。

就我而言,我有几种策略来确定租户、TenantFromX、TenantFromY .. 都按订单运行 Ordered.HIGHEST_PRECEDENCE - 所以越早越好。

在订单Ordered.HIGHEST_PRECEDENCE+1 上,我运行TenantMustExistFilter 过滤器来验证任何策略确实匹配/找到了租户定义

@Log4j2
@Component
@RequiredArgsConstructor
// After TenantFromX(min) but before SessionRepositoryFilter(Session) which is min+50
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
public class TenantMandatoryFilter extends GenericFilterBean
{
  @Override
  public void doFilter(
    ServletRequest request, ServletResponse response,
    FilterChain filterChain
  ) throws ServletException, IOException
  {
    if (TenantStore.getInitMode().isEmpty()) {
      throw new NoTenantException("No tenant identified for request - request blocked");
    }

    try {
      filterChain.doFilter(request, response);
    } finally {
      TenantStore.clear();
    }
  }
}

问题/问题

尽管我抛出了一个运行时异常NoTenantException,该过滤器之后的所有其他过滤器仍然被调用。

例如在Ordered.HIGHEST_PRECEDENCE+50 上调用SessionRepositoryFilter,然后触发spring security FilterProxyChain

TenantMandatoryFilter 验证失败后,如何有效地停止链? 我希望 return;Exception 或只是不调用 filterChain.doFilter(request, response); 就足以结束链执行。

我对这里的流程或想法有误解吗?

尝试

我可以通过替换成功结束链条

if (TenantStore.getInitMode().isEmpty()) {
  throw new NoTenantException("No tenant identified for request - request blocked");
}

if (TenantStore.getInitMode().isEmpty()) {
  response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  return;
}

有趣的是,即使在语义上看起来更正确,以下内容也不起作用。它不起作用意味着,它仍然会调用SessionRepositoryFilterFilterChainProxy

if (TenantStore.getInitMode().isEmpty()) {
  response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid tenant");
  return;
}

我假设是因为sendError 将响应设置为暂停以完成任何其他链(这是我不想要的)。

看起来还是不对,所以如何以正确的方式做到这一点?或者这完全是一个概念缺陷?

【问题讨论】:

  • 我知道我可以用response.reset();response.setStatus(HttpServletResponse.SC_BAD_REQUEST);response.flushBuffer();return; 替换异常,这实际上会停止链条。有趣的是,使用response.reset();response.sendError(HttpServletResponse.SC_BAD_REQUEST);response.flushBuffer();return; 并没有这样做(因为暂停)。从概念上讲,这一切都感觉不对。
  • 通过显式调用或抛出异常发送错误,将导致请求被分派到应用程序的错误页面处理,该处理将再次为该分派调用过滤器。设置状态是正确的做法。
  • 谢谢@AndyWilkinson - 我明白了。因此,稍后将由错误页面处理程序ExceptionTranslationFiltersendError 处理异常,这也很晚。如果您愿意,请回答问题,我会接受您的回答。

标签: spring-boot spring-mvc spring-security spring-session spring-filter


【解决方案1】:

通过显式调用或抛出异常发送错误,将导致请求被分派到应用程序的错误页面处理,该页面处理将再次为该分派调用过滤器。设置状态是正确的做法。

【讨论】:

    猜你喜欢
    • 2017-02-21
    • 1970-01-01
    • 2016-11-09
    • 2013-04-09
    • 2012-02-17
    • 2015-04-09
    • 2016-10-19
    • 1970-01-01
    • 2015-04-02
    相关资源
    最近更新 更多