1. 序章

この記事では、Springセキュリティを使用してHTTPキャッシングを制御する方法について説明します。

デフォルトの動作を示し、その背後にある理由についても説明します。 次に、この動作を部分的または完全に変更する方法を見ていきます。

2. デフォルトのキャッシング動作

キャッシュ制御ヘッダーを効果的に使用することで、リソースをキャッシュし、ネットワークホップを回避するようにブラウザーに指示できます。 これにより、レイテンシが減少し、サーバーの負荷も減少します。

デフォルトでは、Spring Securityは、何も構成しなくても、特定のキャッシュ制御ヘッダー値を設定します。

まず、アプリケーションのSpringセキュリティを設定しましょう。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {}
}

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");

基本的に、これが意味するのは、ブラウザがこの応答をキャッシュしないということです。

これは非効率に見えるかもしれませんが、実際にはこのデフォルトの動作には十分な理由があります– 1人のユーザーがログアウトし、別のユーザーがログインした場合、以前のユーザーのリソースを表示できないようにします。 デフォルトでは何もキャッシュしない方がはるかに安全であり、キャッシュを明示的に有効にする責任は私たちにあります。

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. デフォルトのキャッシュ動作をオフにする

SpringSecurityのデフォルトのキャッシュ制御ヘッダーを完全にオフにすることもできます。 これは非常に危険なことであり、実際にはお勧めできません。 ただし、本当に必要な場合は、 WebSecurityConfigurerAdapter:configureメソッドをオーバーライドして試すことができます。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.headers().disable();
}

それでは、エンドポイントに再度リクエストを送信して、どのような応答が得られるかを確認しましょう。

given()
  .when()
  .get(getBaseUrl() + "/default/users/Michael")
  .then()
  .headers(new HashMap<String, Object>());

ご覧のとおり、キャッシュヘッダーはまったく設定されていません。 繰り返しますが、これは安全ではありませんが、必要に応じてデフォルトのヘッダーをオフにする方法を証明しています。

5. 結論

この記事では、Spring SecurityがデフォルトでHTTPキャッシュを無効にする方法を示し、これは安全なリソースをキャッシュしたくないためであると説明します。 また、適切と思われる場合に、この動作を無効化または変更する方法も確認しました。

これらすべての例とコードスニペットの実装は、GitHubプロジェクトにあります。