I have a weird issue with CORS. The API and web APP are running on different servers.
I enabled CORS on the API using laravel-cors package, and am trying to consume the API from a different server.
I can consume the API using Postman as well as Guzzle Http Clients, but it fails when using Ajax.
When I check the API response; I have the Access-Control-Allow-Origin: * header.
How can I fix this?
we will get this issue when client and server are on different machines.
Spring by default blocks the request from different host clients by throwing invalid cors request exception.
So you should allow all the origins in server side code.
If you are using spring the below snippet will be helpful.
Add the below code in Spring boot main class or in new configuration file.
#Bean
public <HttpSecurity> WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
In VerifyCsrfToken middleware
protected $except = [
'api/*'
];
Related
I am putting together a small service-based platform using various Spring Cloud frameworks. The individual components are as follows:
an Eureka discovery server
a Spring-Config server
an Authentication server
a Zuul gateway server
a REST service
a PostgreSQL server
a simple JQuery-based client running in the browser
(yes this is based on the design presented in Manning's "Spring Microservices in Action")
This all works just fine in development. However I have recently deployed all this server-side stuff to an external server (running docker-compose) and I can no longer access the service endpoints.
When calling the service endpoints via JQuery I get the following error:
Access to XMLHttpRequest at 'https://my.domain.com/api/resource/123/subresource/456' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have tried adding the following to the Zuul server (in the same #EnableZuulProxy Spring boot application class) :
#Bean
public FilterRegsitrationBean corsFilter() {
UrlBaseCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("*", config);
FilterRegistrationBean<CorsFilter> bean =
new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
This yielded the same error.
Any ideas?
In Controller, you need to add another annotation with #RestController/#Controller.
#CrossOrigin
Like this :
#Controller
#CrossOrigin(origins = "*", allowedHeaders = "*")
public class HomeController
Try this one.
OK so I fixed it by removing all Cors configs from the services and added this to the Zuul gateway.
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("POST", "PUT", "GET", "OPTIONS", "DELETE", "HEAD");
}
}
It works but I have no idea why my previous attempts don't (and I obviously hate fixing something without having understood how). So if anyone has any ideas...
Cheers
I have an application that includes a Spring cloud gateway that sits in front of an app which (among other things) supports web socket connections (sockJS). The gateway does a simple url rewrite when it forwards to the app. The two are currently running Spring-Boot 2.0.5.RELEASE and Spring-Cloud Finchley.RELEASE. According to the source I pulled down, this should be using spring-websockets-5.0.9.
When I try to upgrade to 2.1.2.RELEASE and Greenwich.RELEASE for Spring-Boot and Spring-Cloud respectively, my websocket connections start failing because an extra Access-Cloud-Allow-Origin is being injected into the response.
My gateway has a simple CORS filter like this (the values are constants and not relevant):
#Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
Mono<Void> result;
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);
result = Mono.empty();
} else {
result = chain.filter(ctx);
}
} else {
result = chain.filter(ctx);
}
return result;
};
}
And my web socket config on the downstream app is simply this:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
}
If I comment out the .setAllowedOrigins("*") in the registerStompEndpoints method, I correctly get 403 access denied responses, and the response only has the Access-Control-Allow-Origin header as injected by the gateway.
With the method in place as shown here, the websocket response completes as expected with a success response to the caller, but the response header contains both the access control header injected by the gateway plus another Access-Control-Allow-Origin header which is set to the value of the caller (in my case, http://localhost:4200 for the front-end application.) None of the other access control headers are duplicated.
How can I configure the Spring websocket message broker to not inject the Access-Control-Allow-Origin header? This was working, and still works if I roll back to 2.0.5/Finchley.
I faced this issue recently and I was able to resolve it by calling setSupressCors method. The documentation says that
This option can be used to disable automatic addition of CORS headers for SockJS requests.
Here is a code sample:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket/handshake")
.setAllowedOrigins("*")
.withSockJS()
.setSupressCors(true);
}
}
I have a springboot app in which I got a WS that i'm able to request with a REST client.
I also have an angular app and I try to request the WS in it but I got this message :
Cross origin requests are only supported for protocol schemes: http,
data, chrome, chrome-extension, https.
I've added this code :
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
in my configuration class, like said in this tuto : https://spring.io/guides/gs/rest-service-cors/ but it seems that it's not enough. What do I miss? Do I have to do something in the angular app?
Thx
Currently I was experiencing the new Spring reactive stack, and want to use reactive features in Spring Session 2.0.
In traditional Servlet approach, Spring Session provides a HttpSessionStrategy to detect session in cookie or request headers. It is easy to use HeaderHttpSessionStrategy to implement a token like authentication(by default the he name is X-AUTH-TOKEN) for RESTful APIs.
Spring 5 core provides a WebSessionIdResolver to do the same thing for Reactive environment.
But when use it with Spring Security and wish it worked as traditional way, I can not get it work.
The SessionConfig file.
#EnableSpringWebSession
public class SessionConfig {
#Bean
public ReactorSessionRepository sessionRepository() {
return new MapReactorSessionRepository(new ConcurrentHashMap<>());
}
#Bean
public WebSessionIdResolver headerWebSessionIdResolver() {
HeaderWebSessionIdResolver resolver = new HeaderWebSessionIdResolver();
resolver.setHeaderName("X-SESSION-ID");
return resolver;
}
}
The partial SecurityConfig.
#EnableWebFluxSecurity
class SecurityConfig {
#Bean
SecurityWebFilterChain springWebFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeExchange()
.pathMatchers(HttpMethod.GET, "/posts/**").permitAll()
.pathMatchers(HttpMethod.DELETE, "/posts/**").hasRole("ADMIN")
//.pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath)
.anyExchange().authenticated()
.and()
.build();
}
A test rest controller file, it returns the current Session ID.
#RestController
public class SessionRestController {
#GetMapping("/sessionId")
public Map<String, String> sessionId(WebSession session){
Map<String, String> map = new HashMap<>();
map.put("id", session.getId());
return map ;
}
}
When I started up the application, and use curl to access the /sessionId, there is no session info the response header.
curl -v -u "user:password" http://localhost:8080/sessionId
And I got the session id in the query result and put it into request headers to access the protected resources and got 401.
curl -v -X POST -H "X-SESSION-ID:xxxx" http://localhost:8080/posts
Update: A working sample can be found here.
Spring Framework's spring-web module defaults to using it's CookieWebSessionIdResolver, which is based on cookies. If you create an alternative bean of type HeaderWebSessionIdResolver, it will get picked up automatically by Spring Session and switch to a header-based strategy.
In either strategy, it's geared to read the incoming ServerExchange headers, and look up the session id, whether that is reading the Cookie header or the SESSION http header.
These strategies also create response headers, whether that is a set-cookie directive for the client (web browser or your code) to populate the Cookie, or to give you the SESSION header (default name for the HeaderWebSessionIdResolver's header name).
Hopefully my final question to get all this working. Using Spring Security OAuth 2.0.8 and Spring-Web MVC 4.2.3 to expose the OAuth endpoints (the majority of the system uses RESTEasy for the REST endpoints, which has its own CORS filter).
I am trying to use the global default CORS support that is now in Web MVC 4.2.x. However, when issuing a test preflight request against the /oauth/token endpoint, I am always getting returned a 403 Invalid CORS Request response. Sample request from Fiddler is below.
OPTIONS http://localhost:8080/myapp/oauth/token HTTP/1.1
User-Agent: Fiddler
Host: localhost:8080
Origin: http://testfakeorigin.overtherainbow.com
Access-Control-Request-Method: POST
Even though this goes through and is determined to be a proper preflight request, it looks like the request fails in DefaultCorsProcessor at line 81 because the CorsConfiguration is null. Even if I explicitly add a CORS registry mapping in my WebMvcConfigurerAdapter (which shouldn't be necessary according to the docs), the config still ends up being null. Where should I look next?
Before the actual POST, you might automatically be issuing an OPTIONS request. By default, only the method that is specified in your RequestMapping is allowed. Therefore, you will have to explicitly allow the OPTIONS method for the cross origin request.
One way to do that, using the global configuration, is as follows:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "OPTIONS").allowedOrigins("http://testfakeorigin.overtherainbow.com");
}
This would enable cross origin requests for all you mapped requests using the GET, POST, and OPTIONS methods.
You can customize the CORS (Cross-Origin Resource Sharing) of entire app in your #Configuration class, that way all your controllers will be override automatically. Take a look:
#Configuration
#EnableWebSecurity( debug = true )
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/* ... configurations */
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
config.addAllowedMethod(HttpMethod.POST);
config.addAllowedMethod(HttpMethod.GET);
config.addAllowedMethod(HttpMethod.PUT);
config.addAllowedMethod(HttpMethod.DELETE);
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
Note: you can define the methods verbs that will applied in your config
Best Regards!