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 的默認緩存控制頭。 這是一種相當冒險的做法,並不推薦這樣做。 但是,如果我們確實需要這樣做,我們可以嘗試通過創建 <em >SecurityFilterChain</em> 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 緩存的方式,並解釋了這是因為我們不想緩存安全資源。我們還了解到,我們可以根據需要禁用或修改此行為。