Sto sviluppando un’applicazione Spring Boot con un’interfaccia Rest e un dardo fronted.
XMLHttpRequest esegue una richiesta OPTIONS che viene gestita completamente corretta. Dopo questo, la richiesta finale GET (“/ products”) viene emessa e non riesce:
Nessuna intestazione ‘Access-Control-Allow-Origin’ è presente sulla risorsa richiesta. L” http: // localhost: 63343 ‘ di origine non è quindi consentito l’accesso.
Dopo alcune operazioni di debug, ho trovato quanto segue: AbstractHandlerMapping.corsConfiguration è popolato per tutte le sottoclassi tranne RepositoryRestHandlerMapping. In RepositoryRestHandlerMapping nessun corsConfiguration è presente / impostato al momento della creazione e quindi non verrà riconosciuto come cors percorso / risorsa.
=> Nessuna intestazione CORS collegata
Potrebbe essere il problema? Come posso impostarlo?
Classi di configurazione:
@Configuration public class RestConfiguration extends RepositoryRestMvcConfiguration { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowCredentials(false).allowedOrigins("*").allowedMethods("PUT", "POST", "GET", "OPTIONS", "DELETE").exposedHeaders("Authorization", "Content-Type"); } ... }
Ho anche provato a impostare il Cors per annotazione:
@CrossOrigin( methods = RequestMethod.GET, allowCredentials = "false") public interface ProductRepository extends CrudRepository { }
Intestazioni di richieste non elaborate:
GET /products HTTP/1.1 Host: localhost:8080 Connection: keep-alive Cache-Control: max-age=0 authorization: Basic dXNlcjpwYXNzd29yZA== User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/43.0.2357.130 Chrome/43.0.2357.130 Safari/537.36 Content-Type: application/json Accept: */* Referer: http://localhost:63343/inventory-web/web/index.html Accept-Encoding: gzip, deflate, sdch Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Intestazioni di risposta non elaborate:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/hal+json;charset=UTF-8 Transfer-Encoding: chunked Date: Thu, 30 Jul 2015 15:58:03 GMT
Versioni utilizzate: Spring Boot 1.3.0.M2 Spring 4.2.0.RC2
Cosa mi manca?
Infatti, prima di Spring Data REST 2.6 (Ingalls) solo HandlerMapping
istanze di HandlerMapping
create da Spring MVC WebMvcConfigurationSupport
e i controller annotati con @CrossOrigin
erano CORS consapevoli.
Ma ora che DATAREST-573 è stato corretto, RepositoryRestConfiguration
espone ora un getCorsRegistry()
per l’installazione globale e @CrossOrigin
annotazioni @CrossOrigin
sui repository vengono riconosciute, quindi questo è l’approccio consigliato. Vedi https://stackoverflow.com/a/42403956/1092077 risposta per esempi concreti.
Per le persone che devono attenersi a Spring Data REST 2.5 (Hopper) o versioni precedenti, penso che la soluzione migliore sia utilizzare un approccio basato su filtri. Ovviamente potresti utilizzare Tomcat, Jetty o questo , ma CorsFilter
che Spring Framework 4.2 fornisce anche un CorsFilter
che utilizza la stessa logica di elaborazione CORS che si @CrossOrigin
e addCorsMappings(CorsRegistry registry)
. UrlBasedCorsConfigurationSource
un’istanza UrlBasedCorsConfigurationSource
al parametro del costruttore CorsFilter
, è ansible ottenere facilmente qualcosa di potente come il supporto globale CORS nativo di Spring.
Se stai usando Spring Boot (che supporta i bean Filter
), potrebbe essere qualcosa del tipo:
@Configuration public class RestConfiguration { @Bean public FilterRegistrationBean corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; } }
Da quando il treno Ingalls è stato realizzato , il supporto di CORS in Spring Data è ora attivo . Ci sono due modi per affrontare:
L’annotazione @CrossOrigin
con l’indicazione delle origins
, dei methods
e dei allowedHeaders
su un’interfaccia @RepositoryRestResource
.
@CrossOrigin(...) @RepositoryRestResource public interface PageRepository extends CrudRepository { ... }
Una configurazione globale con RepositoryRestConfiguration
all’interno di una class @Configuration
. Contrassegnare i repository con @CrossOrigin
non è necessario.
@Configuration public class GlobalRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.getCorsRegistry() .addMapping(CORS_BASE_PATTERN) .allowedOrigins(ALLOWED_ORIGINS) .allowedHeaders(ALLOWED_HEADERS) .allowedMethods(ALLOWED_METHODS); } }
Per qualche motivo l’approccio suggerito nella risposta accettata sopra non ha funzionato per me dopo l’aggiornamento da Spring Boot 1.5.2 a 1.5.6.
Come sottolineato anche dal commento di @ BigDong, l’eccezione che ho ottenuto è stata:
BeanInstantiationException: Imansible istanziare [javax.servlet.Filter]: il metodo Factory ‘springSecurityFilterChain’ ha gettato un’eccezione; l’eccezione annidata è org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean denominato ‘corsFilter’ dovrebbe essere di tipo ‘org.springframework.web.filter.CorsFilter’, ma in realtà era di tipo ‘org.springframework.boot.web .servlet.FilterRegistrationBean
Ecco quindi cosa mi è venuto in mente per ottenere una configurazione CORS “globale” per tutti gli endpoint nella nostra API REST, indipendentemente dal fatto che siano implementati utilizzando Spring Data Rest o Spring MVC, con tutti gli endpoint protetti da Spring Security.
Non ero in grado di colbind un CorsFilter
alla pipeline di richieste al punto giusto, quindi ho configurato SDR e MVC separatamente, tuttavia utilizzando la stessa configurazione per CorsRegistry
tramite questo helper:
public static void applyFullCorsAllowedPolicy(CorsRegistry registry) { registry.addMapping("/**") // .allowedOrigins("*") // .allowedMethods("OPTIONS", "HEAD", "GET", "PUT", "POST", "DELETE", "PATCH") // .allowedHeaders("*") // .exposedHeaders("WWW-Authenticate") // .allowCredentials(true) .maxAge(TimeUnit.DAYS.toSeconds(1)); }
E poi per MVC:
@Configuration @EnableWebSecurity(debug = true) @EnableGlobalMethodSecurity(prePostEnabled = true) public class CustomWebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // enables CORS as per // https://docs.spring.io/spring-security/site/docs/current/reference/html/cors.html#cors http.cors() .and() // ... } @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { applyFullCorsAllowedPolicy(registry); } }; } }
E poi per SDR:
public class CustomRepositoryRestMvcConfiguration extends RepositoryRestConfigurerAdapter { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.setReturnBodyOnCreate(true); config.setReturnBodyForPutAndPost(true); config.setReturnBodyOnUpdate(true); config.setMaxPageSize(250); config.setDefaultPageSize(50); config.setDefaultMediaType(MediaTypes.HAL_JSON); config.useHalAsDefaultJsonMediaType(true); CustomWebSecurityConfiguration.applyFullCorsAllowedPolicy(config.getCorsRegistry()); }
Ecco qualche ulteriore riferimento sull’argomento che mi ha aiutato a trovare questa risposta: