弹簧4.1.5.RELEASE中的ResourceUrlEncodingFilter启用了springSecurityFilterChain

时间:2015-03-24 23:21:58

标签: java spring spring-mvc spring-security

我试图实现资源版本控制,使我的静态文件(js和css)由spring的VersionResourceResolver根据Spring's documentation动态版本化 我有我的xml配置:

<mvc:resources mapping="/css/**" location="/css/">
    <mvc:resource-chain resource-cache="true" auto-registration="true">
        <mvc:resolvers>
            <mvc:version-resolver>
                <mvc:content-version-strategy patterns="/**"/>
            </mvc:version-resolver>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>
<mvc:resources mapping="/js/**" location="/js/">
    <mvc:resource-chain resource-cache="true" auto-registration="true">
        <mvc:resolvers>
            <mvc:version-resolver>
                <mvc:content-version-strategy patterns="/**"/>
            </mvc:version-resolver>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>

在我的web.xml中添加ResourceUrlEncodingFilter时效果很好:

<filter>
    <filter-name>resourceUrlEncodingFilter</filter-name>
    <filter-class>org.springframework.web.servlet.resource.ResourceUrlEncodingFilter</filter-class>
    <init-param>
        <param-name>addMappingForUrlPatterns</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>resourceUrlEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

唯一的一点是,当textSecurityFilterChain出现在web.xml上时,它不起作用,如果我对springSecurityFilterChain的行进行注释,过滤器可以完美地工作,根据this post似乎是在4.1.2版本上解决的bug,如指定的here

那个静态文件的url只是被完全忽略了,当安全性没有启用时,ResourceUrlEncodingFilter只调用它的encodeURL()方法,如何解决它的任何想法?我认为该bug的解决方案已添加到4.1.5.RELEASE版本中。

2 个答案:

答案 0 :(得分:2)

只有在未启用安全性时才会调用过滤器(ResourceUrlEncodingFilter)这一事实让我相信Spring Security正在拦截对静态资源的调用(并且不允许它们传递给过滤器)。请验证您的Spring Security配置是否允许通过静态资源调用。

假设你的css&#39;和&#39; js&#39;文件夹在src / main / resources下,你可以这样做:

(JavaConfig)

class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }
    ...

}

(XML配置)

...

<http security="none" pattern="/resources/**"/>

...

答案 1 :(得分:1)

我有同样的问题。 看起来它与HttpSessionSecurityContextRepository $ Servlet3SaveToSessionRequestWrapper相关,Spring安全性将其用作HttpServletRequest的包装器。它取代了ResourceUrlEncodingFilter所需的一些关键方法实现。

现在我通过创建两个过滤器来使用丑陋的黑客:

首先这样做(应该是过滤器链中的第一个):

    static final String INITIAL_REQUEST_ATTR = "INITIAL_REQUEST";

     @Override
     protected void doFilterInternal(
        HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
            request.setAttribute(INITIAL_REQUEST_ATTR, request);
            filterChain.doFilter(request, response);
    }

第二个是基本上被黑客攻击的ResourceUrlEncodingFilter副本 映射到我的调度程序servlet(用它替换标准)

public class ResourceUrlEncodingFilter extends GenericFilterBean {

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {
    if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
        throw new ServletException("ResourceUrlEncodingFilter just supports HTTP requests");
    }

    HttpServletRequest initialRequest =
            (HttpServletRequest) request.getAttribute(InitialRequestStoreFilter.INITIAL_REQUEST_ATTR);

    if (initialRequest == null) {
        throw new IllegalStateException("Initial request is not stored");
    }

    filterChain.doFilter(request,
            new ResourceUrlEncodingResponseWrapper(initialRequest, (HttpServletResponse) response));
}

private static class ResourceUrlEncodingResponseWrapper extends HttpServletResponseWrapper {

    private final HttpServletRequest initialRequest;

    /* Cache the index and prefix of the path within the DispatcherServlet mapping */
    private Integer indexLookupPath;

    private String prefixLookupPath;

    ResourceUrlEncodingResponseWrapper(HttpServletRequest initialRequest, HttpServletResponse wrapped) {
        super(wrapped);
        this.initialRequest = initialRequest;
    }

    @Override
    public String encodeURL(String url) {
        ResourceUrlProvider resourceUrlProvider = getResourceUrlProvider();
        if (resourceUrlProvider == null) {
            log.debug("Request attribute exposing ResourceUrlProvider not found");
            return super.encodeURL(url);
        }

        initLookupPath(resourceUrlProvider);
        if (url.startsWith(this.prefixLookupPath)) {
            int suffixIndex = getQueryParamsIndex(url);
            String suffix = url.substring(suffixIndex);
            String lookupPath = url.substring(this.indexLookupPath, suffixIndex);
            lookupPath = resourceUrlProvider.getForLookupPath(lookupPath);
            if (lookupPath != null) {
                return super.encodeURL(this.prefixLookupPath + lookupPath + suffix);
            }
        }

        return super.encodeURL(url);
    }

    private ResourceUrlProvider getResourceUrlProvider() {
        return (ResourceUrlProvider) this.initialRequest.getAttribute(
                ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR);
    }

    private void initLookupPath(ResourceUrlProvider urlProvider) {
        if (this.indexLookupPath == null) {
            UrlPathHelper pathHelper = urlProvider.getUrlPathHelper();
            String requestUri = pathHelper.getRequestUri(this.initialRequest);
            String lookupPath = pathHelper.getLookupPathForRequest(this.initialRequest);
            this.indexLookupPath = requestUri.lastIndexOf(lookupPath);
            this.prefixLookupPath = requestUri.substring(0, this.indexLookupPath);

            if ("/".equals(lookupPath) && !"/".equals(requestUri)) {
                String contextPath = pathHelper.getContextPath(this.initialRequest);
                if (requestUri.equals(contextPath)) {
                    this.indexLookupPath = requestUri.length();
                    this.prefixLookupPath = requestUri;
                }
            }
        }
    }

    private int getQueryParamsIndex(String url) {
        int index = url.indexOf("?");
        return (index > 0 ? index : url.length());
    }
}

}

这样可行,但根据我的意见,这不是一个好的解决方案。 所以希望它会得到解决,或者有人会提供更好的解决方案