Spring Webflux und CORS

Spring Webflux und CORS

1. Überblick

Inprevious post lernten wir die CORS-Spezifikation (Cross-Origin Resource Sharing) und deren Verwendung im Frühjahr kennen.

In diesem kurzen Tutorial werdenwe’ll set up a similar CORS configuration using Spring’s 5 WebFlux framework.

Zunächst werden wir sehen, wie wir den Mechanismus für annotationsbasierte APIs aktivieren können.

Anschließend analysieren wir, wie Sie es für das gesamte Projekt als globale Konfiguration oder mithilfe eines speziellenWebFilteraktivieren können.

2. Aktivieren von CORS für mit Anmerkungen versehene Elemente

Spring stellt die Annotation@CrossOriginbereit, um CORS-Anforderungen für Controller-Klassen und / oder Handler-Methoden zu aktivieren.

2.1. Verwenden von@CrossOrigin für eine Anforderungshandlermethode

Fügen wir diese Anmerkung unserer zugeordneten Anforderungsmethode hinzu:

@CrossOrigin
@PutMapping("/cors-enabled-endpoint")
public Mono corsEnabledEndpoint() {
    // ...
}

Wir verwenden einWebTestClient (wie in Abschnitt 4 erläutert). Testen vonthis post), um die Antwort zu analysieren, die wir von diesem Endpunkt erhalten:

ResponseSpec response = webTestClient.put()
  .uri("/cors-enabled-endpoint")
  .header("Origin", "http://any-origin.com")
  .exchange();

response.expectHeader()
  .valueEquals("Access-Control-Allow-Origin", "*");

Zusätzlich können wir eine Preflight-Anfrage durchführen, um sicherzustellen, dass die CORS-Konfiguration wie erwartet funktioniert:

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");

Die Annotation@CrossOriginhat die folgende Standardkonfiguration:

  • Erlaubt alle Ursprünge (das erklärt den '*' Wert im Antwortheader)

  • Ermöglicht alle Header

  • Alle von der Handler-Methode zugeordneten HTTP-Methoden sind zulässig

  • Anmeldeinformationen sind nicht aktiviert

  • Der Höchstalterwert beträgt 1800 Sekunden (30 Minuten).

Jeder dieser Werte kann jedoch mithilfe der Parameter der Anmerkung überschrieben werden.

2.2. Verwenden von@CrossOrigin auf dem Controller

Diese Annotation wird auch auf Klassenebene unterstützt und wirkt sich auf alle Methoden aus.

Falls die Konfiguration auf Klassenebene nicht für alle unsere Methoden geeignet ist, können wir beide Elemente mit Anmerkungen versehen, um das gewünschte Ergebnis zu erzielen:

@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. Aktivieren von CORS in der globalen Konfiguration

Wir können auch eine globale CORS-Konfiguration definieren, indem wir dieaddCorsMappings()-Methode einerWebFluxConfigurer-Implementierung überschreiben.

Darüber hinaus benötigt die Implementierung die Annotation@EnableWebFlux, um die Spring WebFlux-Konfiguration zu importieren:

@Configuration
@EnableWebFlux
public class CorsGlobalConfiguration implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/**")
          .allowedOrigins("http://allowed-origin.com")
          .allowedMethods("PUT")
          .maxAge(3600);
    }
}

Infolgedessen ermöglichen wir die herkunftsübergreifende Verarbeitung von Anforderungen für dieses bestimmte Pfadmuster.

Die Standardkonfiguration ähnelt der von@CrossOrigin, jedoch sind nur die MethodenGET,HEAD undPOSTzulässig.

Wir können diese Konfiguration auch mit einer lokalen kombinieren:

  • Für die mehrwertigen Attribute wird die resultierende CORS-Konfiguration als Ergänzung jeder Spezifikation verwendet

  • Andererseits haben die lokalen Werte Vorrang vor den globalen Werten für die einwertigen Werte

Die Verwendung dieses Ansatzes ist jedoch für funktionale Endpunkte nicht effektiv.

4. Aktivieren von CORS mitWebFilter

Der beste Weg, CORS auf funktionalen Endpunkten zu aktivieren, ist die Verwendung vonWebFilter.

Wie wirin this post gesehen haben, können wirWebFilters verwenden, um Anforderungen und Antworten zu ändern, während die Implementierung des Endpunkts intakt bleibt.

Spring liefert die integriertenCorsWebFilter, um die Ursprungskonfigurationen einfach zu handhaben:

@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);
}

Dies ist auch für mit Anmerkungen versehene Handler wirksam, kann jedoch nicht mit einer feinkörnigeren@CrossOrigin-Konfiguration kombiniert werden.

Wir müssen berücksichtigen, dassCorsConfigurationkeine Standardkonfiguration hat.

Daher ist die CORS-Implementierung ziemlich restriktiv, sofern nicht alle relevanten Attribute angegeben werden.

Eine einfache Möglichkeit zum Festlegen der Standardwerte ist die Verwendung derapplyPermitDefaultValues()-Methode für das Objekt.

5. Fazit

Abschließend haben wir anhand sehr kurzer Beispiele gelernt, wie CORS für unseren webfluxbasierten Service aktiviert werden kann.

Wir haben verschiedene Ansätze gesehen, deshalb müssen wir jetzt nur noch analysieren, welcher unseren Anforderungen am besten entspricht.

Wir können viele Beispiele inour Github repo finden, zusammen mit Testfällen, in denen wir die meisten Randfälle zu diesem Thema analysieren.