拥有 Multi-Tenancy 应用程序,我想尽早结束没有租户的任何请求。
设置/场景
我使用 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;
}
有趣的是,下面的代码不起作用,尽管它在语义上看起来更正确。它不起作用意味着,它会在此之后调用 SessionRepositoryFilter
和 FilterChainProxy
。
if (TenantStore.getInitMode().isEmpty()) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid tenant");
return;
}
我认为这是因为 sendError
将响应设置为挂起以完成任何其他链(这是我不想要的)。
看起来仍然不对,那么如何以正确的方式做到这一点?或者这完全是一个概念缺陷?
最佳答案
通过显式调用或抛出异常来发送错误,将导致请求被分派(dispatch)到应用程序的错误页面处理,这将再次调用该分派(dispatch)的过滤器。设置状态是正确的做法。
关于spring-boot - 如何在早期 servlet/spring boot 过滤器中强制结束过滤器链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68146232/