Spring Security - Заголовки контроля кэша

Spring Security - Заголовки контроля кэша

1. Вступление

В этой статье мы рассмотрим, как можно контролировать кеширование HTTP с помощью Spring Security.

Мы продемонстрируем его поведение по умолчанию, а также объясним его причины. Затем мы рассмотрим способы изменить это поведение частично или полностью.

2. Поведение кэширования по умолчанию

Эффективно используя заголовки управления кэшем, мы можем дать нашему браузеру указание кэшировать ресурсы и избегать сетевых скачков. Это уменьшает время ожидания, а также нагрузку на наш сервер.

По умолчанию Spring Security устанавливает для нас конкретные значения заголовка элемента управления кэшем, без необходимости что-либо настраивать.

Во-первых, давайте настроим Spring Security для нашего приложения:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {}
}

Мы переопределяемconfigure(), чтобы ничего не делать, это означает, что нам не нужно проходить аутентификацию, чтобы попасть в конечную точку, что позволяет нам сосредоточиться исключительно на тестировании кеширования.

Затем давайте реализуем простую конечную точку REST:

@GetMapping("/default/users/{name}")
public ResponseEntity 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");

По сути, это означает, что браузер никогда не будет кэшировать этот ответ.

Хотя это может показаться неэффективным, на самом деле для такого поведения по умолчанию есть веская причина -If one user logs out and another one logs in, we don’t want them to be able to see the previous users resources. Гораздо безопаснее ничего не кешировать по умолчанию, оставив нам ответственность за явное включение кеширования.

3. Переопределение поведения кэширования по умолчанию

Иногда мы можем иметь дело с ресурсами, которые мы хотим кэшировать. Если мы собираемся включить его, это будет безопаснее всего для каждого ресурса. Это означает, что любые другие ресурсы по-прежнему не будут кэшироваться по умолчанию.

Для этого давайте попробуем переопределить заголовки элементов управления кешем в одном методе-обработчике, используя кешCacheControl. КлассCacheControl - это гибкий конструктор, который упрощает создание различных типов кеширования:

@GetMapping("/users/{name}")
public ResponseEntity 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. Это довольно рискованно, и не рекомендуется. Но мы, если действительно хотим, мы можем попробовать это, переопределив методconfigure дляWebSecurityConfigurerAdapter:

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

Теперь давайте снова сделаем запрос к нашей конечной точке и посмотрим, какой ответ мы получим:

given()
  .when()
  .get(getBaseUrl() + "/default/users/Michael")
  .then()
  .headers(new HashMap());

Как мы видим, заголовки кэша не были установлены вообще. И сноваthis is not secure but proves how we can turn off the default headers if we want to.

7. Заключение

В этой статье показано, как Spring Security по умолчанию отключает кэширование HTTP, и объясняется, что это происходит потому, что мы не хотим кэшировать защищенные ресурсы. Мы также увидели, как можно отключить или изменить это поведение по своему усмотрению.

Реализация всех этих примеров и фрагментов кода можно найти вGitHub project - это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.