Comment activerCORSdans un projet Spring 5 Webflux?
Je ne trouve pas de documentation appropriée.
Voici une autre solution avec le configurateur Webflux.
Note latérale: Son code Kotlin (copié de mon projet), mais vous pouvez facilement le traduire en code Java.
@Configuration
@EnableWebFlux
class WebConfig: WebFluxConfigurer
{
override fun addCorsMappings(registry: CorsRegistry)
{
registry.addMapping("/**")
.allowedOrigins("*") // any Host or put domain(s) here
.allowedMethods("GET, POST") // put the http verbs you want allow
.allowedHeaders("Authorization") // put the http headers you want allow
}
}
J'ai eu du succès avec ce filtre personnalisé:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Configuration
public class CorsConfiguration {
private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN";
private static final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
private static final String ALLOWED_Origin = "*";
private static final String MAX_AGE = "3600";
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_Origin);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers",ALLOWED_HEADERS);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
et org.springframework.boot:spring-boot-starter-web
ne devrait pas être inclus en tant que dépendance - le filtre ne fonctionne pas avec elle.
@Configuration
public class WebFluxConfig {
@Bean
public WebFluxConfigurer corsConfigurer() {
return new WebFluxConfigurerComposite() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("*");
}
};
}
}
qui correspond à:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
pour le printemps mvc.
Si quelqu'un veut une version Kotlin de la réponse de Zufar (fonctionne comme un charme avec les fonctions de routage webflux) sans comprendre en plus comment fonctionnent les conversions SAM de Kotlin, voici le code:
@Bean
fun corsFilter(): WebFilter {
return WebFilter { ctx, chain ->
val request = ctx.request
if (CorsUtils.isCorsRequest(request)) {
val response = ctx.response
val headers = response.headers
headers.add("Access-Control-Allow-Origin", ALLOWED_Origin)
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS)
headers.add("Access-Control-Max-Age", MAX_AGE)
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS)
if (request.method === HttpMethod.OPTIONS) {
response.statusCode = HttpStatus.OK
return@WebFilter Mono.empty<Void>()
}
}
chain.filter(ctx)
}
}
UPDATE Lorsque j'ai commencé à le tester, j'ai trouvé un problème avec cette solution. C'est Ok si vous voulez vraiment autoriser toutes les méthodes. Mais imaginons que vous souhaitiez n'autoriser que POST
et OPTIONS
, par exemple. Et le navigateur essaie d'envoyer PUT
.
Ensuite, une réponse de contrôle en amont indiquera essentiellement "hé, je ne peux servir que POST et OPTIONS, mais mon statut HTTP sera OK
si vous me donnez une requête avec Access-Control-Request-Method=PUT
". Ce devrait être 403 Forbidden
cependant . De plus, la plupart de ces en-têtes, comme Access-Control-Allow-Methods
, ne devraient être ajoutés qu'aux demandes de contrôle en amont, pas toutes les demandes CORS
. Solution:
@Bean
fun corsWebFilter(): CorsWebFilter {
val corsConfig = CorsConfiguration()
corsConfig.allowedOrigins = Arrays.asList(ALLOWED_ORIGINS)
corsConfig.maxAge = MAX_AGE.toLong()
//Notice it's singular. Can't be comma separated list
corsConfig.addAllowedMethod(ALLOWED_METHOD)
corsConfig.addAllowedHeader(ALLOWED_HEADER)
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration(MATCH_ALL_PATH_SEGMENTS, corsConfig)
return CorsWebFilter(source)
}
où
const val MATCH_ALL_PATH_SEGMENTS = "/**"
Grâce à @Dachstein, remplacer les configurations WebMvc par Webflux est la bonne façon d’ajouter la configuration globale CORS ici.
@Configuration
@EnableWebFlux
public class CORSConfig implements WebFluxConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*");
}
}
Voici un lien vers la documentation officielle
https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-cors
Il y a 3 options principales
1) Utilisation de l'annotation @CrossOrigin sur un contrôleur de repos - elle peut être utilisée au niveau de la classe et/ou de la méthode
2) Implémentez la méthode addCorsMapping à partir de WebFluxConfigurer - elle vous donne un lien avec l'objet global CorsRegistry.
3) Définir un composant CorsWebFilter - bon choix pour les terminaux fonctionnels
S'il vous plaît regardez les docs, sont bien expliqués.
Personnellement, j'utilise la troisième option lorsque je veux autoriser l'utilisation de cors lors du développement et que j'ai découplé le backend du module frontal.
Imaginez que vous ayez webflux sur un module de back-end alors que sur le front-end, vous avez une application react ou angulaire. Lors du développement des fonctionnalités frontales, vous pouvez utiliser webpack-dev-server pour le rechargement à chaud tout en exécutant le backend sur netty - le port sera différent et cela posera un problème CORS. Avec la troisième option, vous pouvez facilement lier le @Component à @Profile ("dev") afin que, lorsque vous déployez dans prod, CORS soient activés.