Configurando CORS Global para API Springboot
Tags: cors, frontend, springboot, endpoint
Published: 2023-10-26 20:29:34

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](https://developer.mozilla.org/pt-BR/docs/Web/HTTP/CORS) (Cross-Origin Resource Sharing) e ele sempre apresenta o mesmo erro no console:

![CORS erro - imagem ilustrativa](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/85978znndyotn1l1fodn.png)

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:

```java
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:

```yml
# 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. :blush:

Até qualquer dia... :wink: