Spring Security - Cabeçalhos de controle de cache
1. Introdução
Neste artigo, vamos explorar como podemos controlar o cache HTTP com Spring Security.
Vamos demonstrar seu comportamento padrão e também explicar o motivo por trás dele. Em seguida, examinaremos maneiras de mudar esse comportamento, parcial ou totalmente.
2. Comportamento de cache padrão
Usando cabeçalhos de controle de cache de maneira eficaz, podemos instruir nosso navegador a armazenar recursos em cache e evitar saltos de rede. Isso diminui a latência e também a carga em nosso servidor.
Por padrão, o Spring Security define valores específicos de cabeçalho de controle de cache para nós, sem precisar configurar nada.
Primeiro, vamos configurar o Spring Security para nosso aplicativo:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {}
}
Estamos substituindoconfigure() para não fazer nada, isso significa que não precisaremos ser autenticados para atingir um endpoint, o que nos permite focar puramente no teste de cache.
A seguir, vamos implementar um ponto de extremidade REST simples:
@GetMapping("/default/users/{name}")
public ResponseEntity getUserWithDefaultCaching(@PathVariable String name) {
return ResponseEntity.ok(new UserDto(name));
}
O cabeçalhocache-control resultante terá a seguinte aparência:
[cache-control: no-cache, no-store, max-age=0, must-revalidate]
Finalmente, vamos implementar um teste que atinge o ponto de extremidade e determinar quais cabeçalhos são enviados na resposta:
given()
.when()
.get(getBaseUrl() + "/default/users/Michael")
.then()
.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
.header("Pragma", "no-cache");
Essencialmente, o que isso significa é que um navegador nunca armazenará essa resposta em cache.
Embora isso possa parecer ineficiente, há na verdade uma boa razão para esse comportamento padrão -If one user logs out and another one logs in, we don’t want them to be able to see the previous users resources. É muito mais seguro não armazenar nada em cache por padrão e deixar que sejamos responsáveis por habilitar o cache explicitamente.
3. Substituindo o comportamento padrão de armazenamento em cache
Às vezes, podemos estar lidando com recursos que queremos que sejam armazenados em cache. Se vamos habilitá-lo, seria mais seguro fazer isso por recurso. Isso significa que outros recursos ainda não serão armazenados em cache por padrão.
Para fazer isso, vamos tentar substituir os cabeçalhos de controle de cache em um único método de manipulador, usando o cacheCacheControl. A classeCacheControl é um construtor fluente, o que torna mais fácil para nós criarmos diferentes tipos de cache:
@GetMapping("/users/{name}")
public ResponseEntity getUser(@PathVariable String name) {
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(new UserDto(name));
}
Vamos atingir este ponto final em nosso teste e afirmar que alteramos os cabeçalhos:
given()
.when()
.get(getBaseUrl() + "/users/Michael")
.then()
.header("Cache-Control", "max-age=60");
Como podemos ver, substituímos os padrões e agora nossa resposta será armazenada em cache por um navegador por 60 segundos.
4. Desativando o comportamento padrão de armazenamento em cache
Também podemos desativar completamente os cabeçalhos de controle de cache padrão do Spring Security. Isso é algo arriscado, e não é realmente recomendado. Mas, se realmente quisermos, podemos tentar substituindo o métodoconfigure doWebSecurityConfigurerAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().disable();
}
Agora, vamos fazer uma solicitação ao nosso endpoint novamente e ver a resposta que obtemos:
given()
.when()
.get(getBaseUrl() + "/default/users/Michael")
.then()
.headers(new HashMap());
Como podemos ver, nenhum cabeçalho de cache foi definido. Novamente,this is not secure but proves how we can turn off the default headers if we want to.
7. Conclusão
Este artigo demonstra como o Spring Security desabilita o cache HTTP por padrão e explica que isso ocorre porque não queremos armazenar recursos seguros em cache. Também vimos como podemos desativar ou modificar esse comportamento conforme acharmos adequado.
A implementação de todos esses exemplos e trechos de código pode ser encontrada emGitHub project - este é um projeto Maven, portanto, deve ser fácil de importar e executar como está.