成功了!
Spring 安全文档(http://docs.spring.io/spring-security/site/docs/3.1.x/reference/security-filter-chain.html http://docs.spring.io/spring-security/site/docs/3.1.x/reference/security-filter-chain.html ) say: “Spring Security 只对保护应用程序内的路径感兴趣,因此 contextPath 被忽略。不幸的是,servlet 规范没有准确定义 servletPath 和 pathInfo 的值将包含特定请求 URI 的内容。[...] 该策略是在 AntPathRequestMatcher 类中实现的,它使用 Spring 的 AntPathMatcher 对连接的 servletPath 和 pathInfo 执行不区分大小写的模式匹配,忽略 queryString。”
所以我只是覆盖了servletPath
and contextPath
(即使 Spring Security 不使用它)。另外,我添加了一些小的重定向,因为通常在点击时http://localhost:8080/myContext
您将被重定向到http://localhost:8080/myContext/
Spring Security Antmatcher 不喜欢缺少尾部斜杠。
所以这是我的MultiTenancyFilter
code:
@Component @Order(Ordered.HIGHEST_PRECEDENCE)
public class MultiTenancyFilter extends OncePerRequestFilter {
private final static Pattern pattern = Pattern.compile("^(?<contextPath>/[^/]+)(?<servletPath>.*)$");
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Matcher matcher = pattern.matcher(request.getServletPath());
if(matcher.matches()) {
final String contextPath = matcher.group("contextPath");
final String servletPath = matcher.group("servletPath");
if(servletPath.trim().isEmpty()) {
response.sendRedirect(contextPath+"/");
return;
}
filterChain.doFilter(new HttpServletRequestWrapper(request) {
@Override
public String getContextPath() {
return contextPath;
}
@Override
public String getServletPath() {
return servletPath;
}
}, response);
} else {
filterChain.doFilter(request, response);
}
}
@Override
protected String getAlreadyFilteredAttributeName() {
return "multiTenancyFilter" + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX;
}
}
它只是使用此处提到的 URL 模式提取 contextPath 和 servletPath:https://theholyjava.wordpress.com/2014/03/24/httpservletrequest-requesturirequesturlcontextpathservletpathpathinfoquerystring/ https://theholyjava.wordpress.com/2014/03/24/httpservletrequest-requesturirequesturlcontextpathservletpathpathinfoquerystring/
另外我必须提供一个自定义的getAlreadyFilteredAttributeName
方法,因为否则过滤器被调用两次。 (这导致剥离contextPath
twice)