Reputation: 25770
I need to add CORS filter to my Spring Boot web application.
I have added CORS mappings as described in the following documentation http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html
This is my config:
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
// @formatter:off
registry
.addMapping("/**")
.allowedOrigins(CrossOrigin.DEFAULT_ORIGINS)
.allowedHeaders(CrossOrigin.DEFAULT_ALLOWED_HEADERS)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600L);
// @formatter:on
}
...
}
Right now when I'm trying to access my API I receiving a following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com/api/v1.0/user. (Reason: CORS preflight channel did not succeed).
This is a screenshot from FF console:
What am I doing wrong and how to properly configure CORS headers in order to avoid this issue ?
Upvotes: 49
Views: 129528
Reputation: 1736
AFAIK, for all the http requests, a preflight request is sent to the server in order to check the access of that particular api request. The preflight request is usually a "OPTION" http request which sends the metadata required for the coming request.
So the error, preflight channel didn't succeed means that the preflight request which was sent to the server got blocked or rejected. In most cases, this happens because
As of Spring security 5.4.5 we can basically allow the above mentioned points to check whether this is the underlying problem.
Create or update the class which extends WebMvcConfigurer
@Override
public void addCorsMappings(CorsRegistry registry) {
//The pattern, allowedOrigins and allowedMethods should be restricted to the frontend application url,
//so that CORS attacks won't happen
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}
Here, addMapping takes a parameter of the "API endpoint", we are providing "*" to configure all the endpoints supported by the server.
allowedOrigins corresponds to the UI application paths supported for the mappings we provided above (*)
allowedMethods takes in an array of all the http methods allowed your server.
In a production environment this configuration we provide should be restricted to the appropriate values.
Also, in your configuration class which extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.......
.authenticated();
}
Note the 'http.cors()' methods we provided
Upvotes: 0
Reputation: 81
This was the piece of code that I used for Cors Configurations to work with Spring Boot. It's corsFilter configuration inside main application class.
Application is running on 'http://localhost:4200'
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
corsConfiguration.setAllowedHeaders(Arrays.asList("Origin", "Access-Control-Allow-Origin", "Content-Type",
"Accept", "Authorization", "Origin, Accept", "X-Requested-With",
"Access-Control-Request-Method", "Access-Control-Request-Headers"));
corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization",
"Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
Upvotes: 3
Reputation: 362
If you are using CORS with Spring Security, this is the latest documentation: https://docs.spring.io/spring-security/site/docs/current/reference/html5/#cors
This is similar to the code quoted elsewhere on this page:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors(withDefaults())
...
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Although there are other places where you can configure CORS, it makes sense to do it as part of your security configuration because they are tightly related in that the CORS processing has to happen before the security processing - something that previous posts have noted. The reason given in the above quoted doc is that:
"CORS must be processed before Spring Security because the pre-flight request will not contain any cookies (i.e. the JSESSIONID). If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it."
Adding the .cors() line at the start of the http configuration - as shown above - makes that happen. Otherwise the pre flight OPTIONS request will go unresponded.
Upvotes: 4
Reputation: 49
Step 1: Add this annotation in your controller
@CrossOrigin
public class JobController {}
Step2 : Add this in any of your Configuration
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
This will work only if you have @CrossOrigin annotation on your controller
Upvotes: 0
Reputation: 1000
I still had the CORS error after following the two tutorials:
First I followed the Web Security guide: https://spring.io/guides/gs/securing-web/#scratch
Second I followed the CORS guide: https://spring.io/guides/gs/rest-service-cors/#global-cors-configuration
To resolve my issues after following these guides I had to add http.cors()
to the http security.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
...
}
Adding the .cors()
allows it to use the @Bean
I declared for my CORS configuration.
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:4200");
}
};
}
Upvotes: 5
Reputation: 970
This is very simple and working well. Within the class you wrote for Web Security Configurations, enter this line httpSecury.cors();
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors(); // This enables cors
// Your codes
}
}
Upvotes: 7
Reputation: 461
It's work for me
@Configuration
public class CorsConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS");
}
}
Upvotes: 3
Reputation: 11
if using spring-boot 2 below code is enough to solve cors issue and preflight issue
@Override
public void configure(WebSecurity web) throws Exception {
// web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
web.ignoring().antMatchers("/resources/**", "/index.html", "/login.html", "/partials/**", "/template/**", "/",
"/error/**", "/h2-console", "*/h2-console/*");
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.applyPermitDefaultValues();
config.setAllowCredentials(true);// this line is important it sends only specified domain instead of *
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
Upvotes: 1
Reputation: 525
The current recommended way of doing CORS is
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
// Add more mappings...
}
}
This is base on https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors
But you also need to make sure that CORS is enabled and CSRF is disabled in your WebSecurityConfig file.
I once had an issue where all my POST methods are not working (returning 403 forbiden) while GET methods work just fine but this is solved after CSRF is disabled
Upvotes: 1
Reputation: 25770
I have fixed this issue by creating a new CORS Filter:
@Component
public class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, xsrf-token");
response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(request, response);
}
}
}
and added it to securty configuration:
.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class)
UPDATED - More modern way nowadays which I switched to:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
...
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Upvotes: 118
Reputation: 175
For what its worth, the following combination solution worked for me:
1.
@Configuration
public class CorsConfiguration {
//This can be used in combination with @CrossOrigin on the controller & method.
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD","OPTIONS")
.allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept");
}
};
}
}
2. @CrossOrigin
on the RestController class. Having @CrossOrigin
reads the @RequestMapping
annotations and the HTTP methods in it. Rest of the requests are rejected with CORS error.
But you will be out of luck with the above solution if you want to use spring security in your project.
I am using spring boot version 1.5.4.RELEASE.
Upvotes: 3
Reputation: 527
Had the same issue getting CORS to work with spring data rest, this was the filter code I used.
/**
* Until url{https://jira.spring.io/browse/DATAREST-573} is fixed
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
//config.setAllowCredentials(true); // you USUALLY want this
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
Upvotes: 21
Reputation: 198
Proper handling of the pre-flight OPTIONS request is necessary, but NOT SUFFICIENT for cross-site resource requests to work.
After the OPTIONS request comes back with satisfactory headers, all responses to any subsequent requests to the same URL also have to have the necessary "Access-Control-Allow-Origin" header, otherwise the browser will swallow them, and they won't even show up in the debugger window. https://stackoverflow.com/a/11951532/5649869
Upvotes: 0