Quando temos a necessidade de consumir (ou enviar) dados de uma API para apresentar no frontend construímos diversos endpoints nela para nos auxiliar nesta tarefa e com isso sempre barramos no famigerado CORS (Cross-Origin Resource Sharing) e ele sempre apresenta o mesmo erro no console:
Então a primeira ação que temos é ir na nossa API, procurar a Controller e adicionar acima no endpoint a anotação do Springframework...
@CrossOrigin ou @CrossOrigin(origins = "*")
...nos livrar do problema e seguir o desenvolvimento da tarefa.
Então nossa API vai crescendo e todo o endpoint exposto para o front vai receber essa mesma anotação do @CrossOrigin
.
Chega um momento que você se pergunta se ainda é realmente necessário ter essa anotação ali, ou a validação do Sonar está avisando que esse CORS é uma vulnerabilidade no seu código.
Há uma maneira, até simples, de fazer essa configuração de CORS porém num escopo Global, sem precisar adicionar em todos os endpoints. Para isso, basta criar a seguinte classe na sua estrutura:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
class CORSConfiguration implements WebMvcConfigurer {
@Value("${config.cors.allowed-origins}")
String[] origins;
@Value("${config.cors.allowed-headers}")
String[] headers;
@Value("${config.cors.allowed-methods}")
String[] methods;
@Value("${config.cors.max-age}")
long maxAge;
@Value("${config.cors.exposed-headers}")
String[] exposed;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true).maxAge(maxAge)
.allowedOriginPatterns(origins).allowedHeaders(headers)
.allowedMethods(methods).exposedHeaders(exposed);
}
}
e também alterar o seu arquivo properties.yml
adicionado a seguinte estrutura:
# CORS config
config:
cors:
allowed-origins: http://localhost:4200, https://www.url-do-front.com.br
allowed-methods: GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD
max-age: 3600
allowed-headers: "*"
exposed-headers: "*"
Explicando aqui:
A classe de configuração implementa a interface nativa do Spring MVC chamada WebMvcConfigurer
e com isso você precisa sobrescrever o método: void addCorsMappings(CorsRegistry registry)
.
Esse método, adiciona em tempo de configuração, as configurações de CORS informadas do arquivo .yml
que são recuperadas de lá pela anotação @Value
, também do Spring.
Nota: No método addCorsMapping
, para a classe CorsRegistry
, precisa adicionar o método allowCredentials(true)
, com ele o Swagger não ficará solicitando credenciais de acesso para carregar a página inicial.
Então quando você der o start no projeto, as configurações serão carregadas e adicionadas ao contexto do CORS, com isso não precisa mais da anotação @CrossOrigin
em cada endpoint.
Mas claro, lembrando que cada um tem sua necessidade de implementação do CORS, que isso varia de acordo com cada projeto.
Para minha necessidade atual, funcionou perfeitamente. 😊
Até qualquer dia... 😉
Top comments (2)
Sua dica de externalizar os dados pro CORS, colocando no
application.yml
foi bem legal.Se vc estiver usando Spring Boot, é bom ficar atento com o uso da anotação
@EnableWebMvc
.Quando vc usa esta anotação em conjunto com
@Configuration
vc sobrescreve a auto-configuração que o Spring Boot traz pra gente.Nisso vc pode acabar perdendo algumas configurações que podem te fazer falta.
Se vc quer tirar proveito da auto-configuração do Spring Boot e apenas adicionar a configurações do CORS, basta usar apenas
@Configuration
.Isto é o que a documentação diz:
E também:
Fonte: docs.spring.io/spring-boot/docs/3....
Bem interessante esse ponto. Muito obrigado pela dica.