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

Posted

技术标签:

【中文标题】如何使用 Spring MVC 和 Spring Security 为资源处理程序启用 HTTP 缓存【英文标题】:How to enable HTTP caching for the resource handler with Spring MVC and Spring Security 【发布时间】:2014-09-26 14:24:53 【问题描述】:

我希望为一些静态资源(例如图像)启用 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 资源处理程序更好的解决方案?

【问题讨论】:

即使覆盖/实现资源处理程序也无济于事。 Spring Security 默认禁用安全资源的缓存。如果您不希望禁用这些资源的缓存。这可以使用HttpSecurity 来完成,http.antMatcher("/static/**").headers().disable() 会禁用 Spring Security 设置的所有标头。这也在 Spring Security 参考指南中的 here 中进行了解释。 谢谢 M. Deinum。另一个问题是配置已经有一个antMatchers() 调用,如下所示:http.authorizeRequests().antMatchers("/login", "/static/public/**").permitAll().anyRequest().authenticated()。如何在不覆盖上述antMatchers() 规则的情况下将headers().disable() 规则应用于“/static/**”? 没关系,添加另一个或使用and() 链接多个配置。类似authenticated().and().headers().disabled() 我想禁用“/static/**”的 Spring Security 标头。我了解您的建议会为所有请求或与现有 antMatchers() 规则匹配的请求禁用它们。 不...您的理解不正确...您也可以随时添加一个额外的antMatcher 元素。它们都合并在一起了。 【参考方案1】:

您可以使用 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>

使用注解来配置缓存拦截器的方式如下。 在您的网络配置类中,您可以为 WebContentInterceptor 类添加一个 bean 并将其添加到拦截器列表中。

@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());

请参考this site 了解它是如何完成的。

【讨论】:

似乎 Spring Security 在这些拦截器运行后设置了它的缓存预防标头,因此您示例中的代码对 Spring Security 没有影响。 也需要addPathPatterns("/static/*") 现在都已弃用。新方法是什么? 这是新方法:WebContentInterceptor 拦截器 = new WebContentInterceptor();拦截器.setCacheControl(CacheControl.youNeeds()); registry.addInterceptor(拦截器);【参考方案2】:

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

sn -p以下可用于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

【讨论】:

这会覆盖Cache-Control 标头的max-age 部分。但是,它不会删除该标头的 must-revalidate 部分,也不会删除 Pragma: no-cache 标头。 文档中提到的其他选项是直接设置标题,HttpServletResponse.setHeader(String,String) 你建议在哪里调用 setHeader()?我尝试了很多地方,每次 Spring Security 都会覆盖标题。安装我自己的 servlet 过滤器是唯一的方法吗? 刚试了一下,好像不行,我的错。这似乎是一个悬而未决的问题jira.spring.io/browse/SEC-2728 我刚刚尝试了这里提到的解决方案。工作得很漂亮。 ***.com/questions/29530575/…【参考方案3】:

您已经设置好缓存。 must-revalidate 意味着一旦缓存过期(3600 秒)就不要再使用它了,所以我认为你的响应头是正确的。

【讨论】:

很好,must-revalidate 不会阻止缓存。然而must-revalidate 语义并不是人们通常想要的,而且Pragma: no-cache 通常会阻止缓存。

以上是关于如何使用 Spring MVC 和 Spring Security 为资源处理程序启用 HTTP 缓存的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring MVC、Spring Security 和 FreeMarker 在每个页面上显示用户名

spring mvc中如何过滤form提交数据中的空格?

spring mvc如何使用resource

我们如何在 Spring MVC 项目中使用 Spring Cloud Sleuth?

如何使用 Spring MVC 和 Spring Security 更新有关授权用户的信息并将其保存在数据库中

spring mvc 如何配置最简洁的