问题 如何使用Spring MVC和Spring Security为资源处理程序启用HTTP缓存


我希望为一些静态资源启用HTTP缓存,例如图像,其访问受到Spring Security的限制。 (这些资源不是安全关键,但也不应公开访问)。如何避免让Spring Security添加禁用缓存的HTTP响应头?

如果我加 setCachePeriod() 进入我的资源处理程序注册 WebMvcConfigurerAdapter.addResourceHandlers() 如下:

registry.addResourceHandler("/static/**")
  .addResourceLocations("classpath:/static/").setCachePeriod(3600);

仍然返回资源以及禁用缓存的以下标头:

Cache-Control: max-age=3600, must-revalidate
Expires: Mon, 04 Aug 2014 07:45:36 GMT
Pragma: no-cache

我想避免在项目中引入任何XML配置,该项目目前仅使用Java注释配置。

有没有比扩展Spring资源处理程序更好的解决方案?


6232
2017-08-04 06:53


起源

即使覆盖/实现资源处理程序也无济于事。默认情况下,Spring Security会禁用安全资源的缓存。如果您不希望对这些资源禁用此缓存。这可以使用 HttpSecurity 就像是 http.antMatcher("/static/**").headers().disable() 禁用Spring Security设置的所有标头。这也解释了 这里 在Spring Security Reference Guide中。 - M. Deinum
谢谢M. Deinum。另一个问题是配置已经有了 antMatchers() 调用如下: http.authorizeRequests().antMatchers("/login", "/static/public/**").permitAll().anyRequest().authenticated()。我该如何申请 headers().disable() 规则为“/ static / **”而不覆盖上述内容 antMatchers() 规则? - Samuli Kärkkäinen
无所谓,添加另一个或链接多个配置 and()。就像是 authenticated().and().headers().disabled()。 - M. Deinum
我想禁用“/ static / **”的Spring Security标头。我理解您的建议会针对所有请求或与现有请求匹配的请求禁用它们 antMatchers() 规则。 - Samuli Kärkkäinen
不......你的理解不正确......你也可以随时添加额外的 antMatcher 元件。它们都合并在一起。 - M. Deinum


答案:


您可以使用webContentInterceptor资源来允许静态资源缓存。

<mvc:interceptors>
    <mvc:interceptor>
    <mvc:mapping path="/static/*"/>
        <bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
            <property name="cacheSeconds" value="31556926"/>
            <property name="useExpiresHeader" value="true"/>
            <property name="useCacheControlHeader" value="true"/>
            <property name="useCacheControlNoStore" value="true"/>
        </bean>
   </mvc:interceptor>
</mvc:interceptors>

使用注释来配置缓存拦截器是按照以下方式完成的。 在您的Web配置类中,您可以添加一个bean WebContentInterceptor 类并将其添加到拦截器列表中。

@Bean
public WebContentInterceptor webContentInterceptor() {
    WebContentInterceptor interceptor = new WebContentInterceptor();
    interceptor.setCacheSeconds(31556926);
    interceptor.setUseExpiresHeader(true);;
    interceptor.setUseCacheControlHeader(true);
    interceptor.setUseCacheControlNoStore(true);
    return interceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(webContentInterceptor());
}

参考 这个网站 看看它是如何完成的。


8
2017-10-31 06:26



在这些拦截器运行后,Spring Security似乎会设置其缓存防护标头,因此您的示例中的代码对Spring Security没有任何影响。 - Samuli Kärkkäinen
需要 addPathPatterns("/static/*") 同样 - sura2k
现在全部弃用了。新方法是什么? - Benny Bottema
这是新方法:WebContentInterceptor interceptor = new WebContentInterceptor(); interceptor.setCacheControl(CacheControl.youNeeds()); registry.addInterceptor(拦截); - Benny Bottema


Spring 4文档有这个解决方案,“如果你真的想要缓存特定的响应,你的应用程序可以有选择地调用 HttpServletResponse.setHeader(String,String) 覆盖Spring Security设置的标头“。这有助于确保正确缓存CSS,JavaScript和图像等内容。

下面的代码片段可以用于springmvc配置,

@EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
        .addResourceHandler("/resources/**")
        .addResourceLocations("/resources/")
        .setCachePeriod(31556926);
  }

// ...
}

以供参考: http://docs.spring.io/spring-security/site/docs/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#headers-cache-control


1
2017-11-04 10:41



这确实覆盖了 max-age 的一部分 Cache-Control 头。但它不会删除 must-revalidate 那个标题的一部分,也不是 Pragma: no-cache 头。 - Samuli Kärkkäinen
doc中提到的其他选项是直接设置头,HttpServletResponse.setHeader(String,String) - SunilGiri
你在哪里建议调用setHeader()?我尝试了各种各样的地方,每次Spring Security都会覆盖标题。是否只能安装我自己的servlet过滤器? - Samuli Kärkkäinen
刚尝试过,似乎没有用,我的不好。这似乎是一个悬而未决的问题 jira.spring.io/browse/SEC-2728 - SunilGiri
我刚试过这里提到的解决方案。工作得很漂亮。 stackoverflow.com/questions/29530575/... - dipan66


您已经设置了缓存。 必重新验证 意味着一旦缓存过期(3600秒)不再使用它,所以你认为你的响应标题对你想要的是正确的。


0
2017-11-04 16:54



好点 must-revalidate 不会阻止缓存。但是,那 must-revalidate 语义不是人们通常想要的,而且 Pragma: no-cache 通常会阻止缓存。 - Samuli Kärkkäinen