一尘不染

Spring Boot:注入自定义上下文路径

spring-boot

我正在运行带有嵌入式Tomcat的Spring Boot 1.2.3应用程序。

我想基于URL的第一部分在每个请求上注入自定义contextPath。

例子:

  1. http://localhost:8080/foo有默认情况下contextPath="",应该得到contextPath="foo"

  2. http://localhost:8080/foo/bar有默认情况下contextPath="",应该得到contextPath="foo"

(没有路径的网址应保持原样)

我试着写一个定制的javax.servlet.Filter@Order(Ordered.HIGHEST_PRECEDENCE),但好像我失去了一些东西。这是代码:

@Component @Order(Ordered.HIGHEST_PRECEDENCE)
public class MultiTenancyFilter implements Filter {
    private final static Pattern pattern = Pattern.compile("^/(?<contextpath>[^/]+).*$");

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest req = (HttpServletRequest) request;
        final String requestURI = req.getRequestURI();

        Matcher matcher = pattern.matcher(requestURI);
        if(matcher.matches()) {
            chain.doFilter(new HttpServletRequestWrapper(req) {
                @Override
                public String getContextPath() {
                    return "/"+matcher.group("contextpath");
                }
            }, response);
        }
    }

    @Override public void init(FilterConfig filterConfig) throws ServletException {}
    @Override public void destroy() {}
}

这应该只是在第一个字符串之后/和第二个字符串之前(如果有)之前获取String /,然后将其用作返回值getContextPath()


但是Spring @Controller @RequestMapping和Spring Security
antMatchers("/")似乎并不尊重它。两者仍然像工作contextPath=""


如何动态覆盖每个请求的上下文路径?


阅读 695

收藏
2020-05-30

共1个答案

一尘不染

得到它的工作!

Spring Security docs ( http://docs.spring.io/spring- security/site/docs/3.1.x/reference/security-filter-chain.html ) say: “Spring
Security is only interested in securing paths within the application, so the
contextPath is ignored. Unfortunately, the servlet spec does not define
exactly what the values of servletPath and pathInfo will contain for a
particular request URI. […] The strategy is implemented in the class
AntPathRequestMatcher which uses Spring’s AntPathMatcher to perform a case-
insensitive match of the pattern against the concatenated servletPath and
pathInfo, ignoring the queryString.”

所以我只是重写了servletPathand contextPath(即使Spring
Security不使用它)。另外,我添加了一些小的重定向,因为通常在命中时将http://localhost:8080/myContext您重定向到,http://localhost:8080/myContext/并且Spring
Securities Ant Matcher不喜欢缺少的斜杠。

所以这是我的MultiTenancyFilter代码:

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

另外,我必须提供一个自定义getAlreadyFilteredAttributeName方法,因为否则过滤器将被调用两次。(这导致contextPath两次剥离)

2020-05-30