Spring Webflux e CORS
1. Visão geral
Em aprevious post, aprendemos sobre a especificação Cross-Origin Resource Sharing (CORS) e como usá-la no Spring.
Neste tutorial rápido,we’ll set up a similar CORS configuration using Spring’s 5 WebFlux framework.
Em primeiro lugar, veremos como podemos ativar o mecanismo em APIs baseadas em anotação.
Em seguida, analisaremos como habilitá-lo em todo o projeto como uma configuração global ou usando umWebFilter especial.
2. Habilitando o CORS em elementos anotados
Spring fornece a anotação@CrossOrigin para habilitar solicitações CORS em classes de controlador e / ou métodos de tratamento.
2.1. Usando@CrossOrigin em um método de manipulador de solicitação
Vamos adicionar esta anotação ao nosso método de solicitação mapeado:
@CrossOrigin
@PutMapping("/cors-enabled-endpoint")
public Mono corsEnabledEndpoint() {
// ...
}
Usaremos umWebTestClient (como explicamos na seção '4. Teste 'dethis post) para analisar a resposta que obtemos deste endpoint:
ResponseSpec response = webTestClient.put()
.uri("/cors-enabled-endpoint")
.header("Origin", "http://any-origin.com")
.exchange();
response.expectHeader()
.valueEquals("Access-Control-Allow-Origin", "*");
Além disso, podemos experimentar uma solicitação de comprovação para garantir que a configuração do CORS esteja funcionando conforme o esperado:
ResponseSpec response = webTestClient.options()
.uri("/cors-enabled-endpoint")
.header("Origin", "http://any-origin.com")
.header("Access-Control-Request-Method", "PUT")
.exchange();
response.expectHeader()
.valueEquals("Access-Control-Allow-Origin", "*");
response.expectHeader()
.valueEquals("Access-Control-Allow-Methods", "PUT");
response.expectHeader()
.exists("Access-Control-Max-Age");
A anotação@CrossOrigin tem a seguinte configuração padrão:
-
Permite todas as origens (que explica o valor ‘* 'no cabeçalho da resposta)
-
Permite todos os cabeçalhos
-
Todos os métodos HTTP mapeados pelo método manipulador são permitidos
-
Credenciais não estão ativadas
-
O valor de "idade máxima" é de 1800 segundos (30 minutos)
No entanto, qualquer um desses valores pode ser substituído usando os parâmetros da anotação.
2.2. Usando@CrossOrigin no controlador
Essa anotação também é suportada no nível de classe e afetará todos os seus métodos.
Caso a configuração de nível de classe não seja adequada para todos os nossos métodos, podemos anotar ambos os elementos para obter o resultado desejado:
@CrossOrigin(value = { "http://allowed-origin.com" },
allowedHeaders = { "example-Allowed" },
maxAge = 900
)
@RestController
public class CorsOnClassController {
@PutMapping("/cors-enabled-endpoint")
public Mono corsEnabledEndpoint() {
// ...
}
@CrossOrigin({ "http://another-allowed-origin.com" })
@PutMapping("/endpoint-with-extra-origin-allowed")
public Mono corsEnabledWithExtraAllowedOrigin() {
// ...
}
// ...
}
3. Habilitando o CORS na configuração global
Também podemos definir uma configuração CORS global substituindo o métodoaddCorsMappings() de uma implementaçãoWebFluxConfigurer.
Além disso, a implementação precisa da anotação@EnableWebFlux para importar a configuração Spring WebFlux:
@Configuration
@EnableWebFlux
public class CorsGlobalConfiguration implements WebFluxConfigurer {
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**")
.allowedOrigins("http://allowed-origin.com")
.allowedMethods("PUT")
.maxAge(3600);
}
}
Como resultado, estamos habilitando o tratamento de solicitações de origem cruzada para esse padrão de caminho específico.
A configuração padrão é semelhante à de@CrossOrigin, mas apenas com os métodosGET,HEAD ePOST permitidos.
Também podemos combinar essa configuração com uma configuração local:
-
Para os atributos de valores múltiplos, a configuração CORS resultante será a adição de cada especificação
-
Por outro lado, os valores locais terão precedência sobre os globais para os de valor único
Porém, o uso dessa abordagem não é eficaz para terminais funcionais.
4. Habilitando CORS com umWebFilter
A melhor maneira de habilitar o CORS em terminais funcionais é usando umWebFilter.
Como vimosin this post, podemos usarWebFilters para modificar solicitações e respostas, mantendo a implementação do endpoint intacta.
O Spring forneceCorsWebFilter embutido para lidar facilmente com as configurações de origem cruzada:
@Bean
CorsWebFilter corsWebFilter() {
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.setAllowedOrigins(Arrays.asList("http://allowed-origin.com"));
corsConfig.setMaxAge(8000L);
corsConfig.addAllowedMethod("PUT");
corsConfig.addAllowedHeader("example-Allowed");
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig);
return new CorsWebFilter(source);
}
Isso também é eficaz para manipuladores anotados, mas não pode ser combinado com uma configuração@CrossOrigin mais refinada.
Devemos ter em mente queCorsConfiguration não possui uma configuração padrão.
Portanto, a menos que especifiquemos todos os atributos relevantes, a implementação do CORS será bastante restritiva.
Uma maneira simples de definir os valores padrão é usando o métodoapplyPermitDefaultValues() no objeto.
5. Conclusão
Em conclusão, aprendemos com exemplos muito curtos de como habilitar o CORS em nosso serviço baseado em webflux.
Vimos abordagens diferentes, portanto, tudo o que precisamos fazer agora é analisar qual deles se adapta melhor aos nossos requisitos.
Podemos encontrar muitos exemplos emour Github repo, junto com casos de teste onde analisamos a maioria dos casos extremos relacionados a este tópico.