1. 概述
本篇文章将探讨如何通过Spring Security控制HTTP缓存。我们将展示其默认行为,并解释其背后的逻辑,然后讨论如何部分或完全改变这种行为。
2. 默认缓存行为
有效地使用缓存控制头,我们可以指导浏览器缓存资源,避免网络跳转,从而减少延迟并减轻服务器负载。默认情况下,Spring Security会为我们设置特定的缓存控制头,无需我们进行任何配置。
首先,让我们为应用程序设置Spring Security:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.build();
}
}
我们重写了configure()
方法,使其无操作,这样就不需要认证即可访问端点,以便专注于纯粹的缓存测试。
接下来,实现一个简单的REST端点:
@GetMapping("/default/users/{name}")
public ResponseEntity<UserDto> getUserWithDefaultCaching(@PathVariable String name) {
return ResponseEntity.ok(new UserDto(name));
}
响应中的cache-control
头看起来像这样:
[cache-control: no-cache, no-store, max-age=0, must-revalidate]
最后,实现一个测试,调用端点并断言响应中发送的头信息:
given()
.when()
.get(getBaseUrl() + "/default/users/Michael")
.then()
.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
.header("Pragma", "no-cache");
基本上这意味着浏览器永远不会缓存这个响应。虽然这可能看起来效率不高,但默认行为背后有一个好理由:如果一个用户登出,另一个用户登录,我们不希望他们能看到前一个用户的资源。 默认不缓存任何内容更为安全,让我们负责明确启用缓存。
3. 覆盖默认缓存行为
有时,我们可能处理的是确实希望被缓存的资源。如果要启用它,最好按资源进行。这意味着其他资源仍然默认不会被缓存。
要做到这一点,我们可以尝试在单个处理器方法中使用CacheControl
缓存头来覆盖默认值。CacheControl
类是一个链式构建器,使我们能够轻松创建不同类型的缓存:
@GetMapping("/users/{name}")
public ResponseEntity<UserDto> getUser(@PathVariable String name) {
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(new UserDto(name));
}
在测试中请求这个端点,并断言我们已更改了头信息:
given()
.when()
.get(getBaseUrl() + "/users/Michael")
.then()
.header("Cache-Control", "max-age=60");
如我们所见,我们已覆盖默认值,现在我们的响应将在浏览器中缓存60秒。
4. 关闭默认缓存行为
我们还可以完全关闭Spring Security的默认缓存控制头。这是一项相当冒险的操作,不建议这样做。但如果我们真的想这么做,可以通过创建SecurityFilterChain
bean来尝试:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.headers().disable();
return http.build();
}
现在,再次请求我们的端点,看看我们得到什么响应:
given()
.when()
.get(getBaseUrl() + "/default/users/Michael")
.then()
.headers(new HashMap<String, Object>());
如我们所见,根本没有设置任何缓存头。再次强调,这不安全,但证明了如果我们愿意,可以如何关闭默认头信息。
5. 总结
本文展示了Spring Security如何默认禁用HTTP缓存,并解释了这是因为我们不想缓存安全资源。我们也了解了如何根据需要调整或关闭这种行为。
所有示例和代码片段的实现可以在GitHub项目中找到。