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<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 по умолчанию. Это довольно рискованная вещь, и на самом деле не рекомендуется. Но если мы действительно этого хотим, мы можем попробовать это, переопределив метод configure
WebSecurityConfigurerAdapter:
@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 .