Reputation: 1089
We added Spring Security
to our existing project.
From this moment on we get a 401 No 'Access-Control-Allow-Origin' header is present on the requested resource
error from the our server.
That's because no Access-Control-Allow-Origin
header is attached to the response. To fix this we added our own filter which is in the Filter
chain before the logout filter, but the filter does not apply for our requests.
Our Error:
XMLHttpRequest cannot load
http://localhost:8080/getKunden
. No 'Access-Control-Allow-Origin' header is present on the requested resource. Originhttp://localhost:3000
is therefore not allowed access. The response had HTTP status code 401.
Our Security configuration:
@EnableWebSecurity
@Configuration
@ComponentScan("com.company.praktikant")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilter filter;
@Override
public void configure(HttpSecurity http) throws Exception {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
source.registerCorsConfiguration("/**", config);
http.addFilterBefore(new MyFilter(), LogoutFilter.class).authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/*").permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
}
}
Our filter
@Component
public class MyFilter extends OncePerRequestFilter {
@Override
public void destroy() {
}
private String getAllowedDomainsRegex() {
return "individual / customized Regex";
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String origin = "http://localhost:3000";
response.addHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers",
"content-type, x-gwt-module-base, x-gwt-permutation, clientid, longpush");
filterChain.doFilter(request, response);
}
}
Our Application
@SpringBootApplication
public class Application {
public static void main(String[] args) {
final ApplicationContext ctx = SpringApplication.run(Application.class, args);
final AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CORSConfig.class);
annotationConfigApplicationContext.refresh();
}
}
Our filter is registered from spring-boot:
2016-11-04 09:19:51.494 INFO 9704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'myFilter' to: [/*]
Our generated filterchain:
2016-11-04 09:19:52.729 INFO 9704 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5d8c5a8a, org.springframework.security.web.context.SecurityContextPersistenceFilter@7d6938f, org.springframework.security.web.header.HeaderWriterFilter@72aa89c, org.springframework.security.web.csrf.CsrfFilter@4af4df11, com.company.praktikant.MyFilter@5ba65db2, org.springframework.security.web.authentication.logout.LogoutFilter@2330834f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@396532d1, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4fc0f1a2, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2357120f, org.springframework.security.web.session.SessionManagementFilter@10867bfb, org.springframework.security.web.access.ExceptionTranslationFilter@4b8bf1fb, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@42063cf1]
The Response: Response headers
We tried the solution from spring as well but it didn't work! The annotation @CrossOrigin in our controller didn't help either.
Tried the solution from @Piotr Sołtysiak. The cors filter isn't listed in the generated filter chain and we still get the same error.
2016-11-04 10:22:49.881 INFO 8820 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4c191377, org.springframework.security.web.context.SecurityContextPersistenceFilter@28bad32a, org.springframework.security.web.header.HeaderWriterFilter@3c3ec668, org.springframework.security.web.csrf.CsrfFilter@288460dd, org.springframework.security.web.authentication.logout.LogoutFilter@1c9cd096, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@3990c331, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1e8d4ac1, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2d61d2a4, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@380d9a9b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@abf2de3, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2a5c161b, org.springframework.security.web.session.SessionManagementFilter@3c1fd3e5, org.springframework.security.web.access.ExceptionTranslationFilter@3d7055ef, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5d27725a]
Btw we are using spring-security version 4.1.3.!
Upvotes: 67
Views: 261670
Reputation: 189
This worked for my Angular project
@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: 0
Reputation: 131
Beginning with version 5.7.0-M2, Spring deprecates the use of WebSecurityConfigureAdapter
. So, following the recommended guildelines
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors(AbstractHttpConfigurer::disable) //...other config
return http.build();
}
Like a stupid person I just wasted an entire day on this because I was sending the default 'text/plain'
content-type instead of 'application/json'
which is what my spring controllers where expecting.
Upvotes: 0
Reputation: 113
After 2 days of research,i fix the problem.I am using spring boot 3.1.2 and spring security 6.1.2 with jwt token.Just add this class in your codebase.
@Configuration
@EnableWebMvc
public class WebConfig {
private static final Long MAX_AGE = 3600L;
private static final int CORS_FILTER_ORDER = -102;
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:5173");
config.setAllowedHeaders(Arrays.asList(
HttpHeaders.AUTHORIZATION,
HttpHeaders.CONTENT_TYPE,
HttpHeaders.ACCEPT));
config.setAllowedMethods(Arrays.asList(
HttpMethod.OPTIONS.name(),
HttpMethod.GET.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name()));
config.setMaxAge(MAX_AGE);
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
// should be set order to -100 because we need to CorsFilter before SpringSecurityFilter
bean.setOrder(CORS_FILTER_ORDER);
return bean;
}
}
Do not use * on config.addAllowedOrigin() method argument.Explicitly define the domain you need to allow.
Upvotes: 0
Reputation: 82
Use below sample
@Configuration
@EnableConfigurationProperties(BasicAuthConfigProperties.class)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final BasicAuthConfigProperties basicAuth;
public SecurityConfiguration(BasicAuthConfigProperties basicAuth) {
this.basicAuth = basicAuth;
}
protected void configure(HttpSecurity http) throws Exception {
http.cors();
}
}
Upvotes: 0
Reputation: 414
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.....
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/**").authenticated().and().httpBasic().and().csrf().disable();
}
@Bean
protected CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
......
}
Upvotes: 0
Reputation: 5649
To enable CORS Globally you need to make changes in two places, if you are also using spring security with boot:
1. Spring Boot:
@Configuration
public class CorsConfiguration extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*")
.allowCredentials(true);
}
}
You can do the same in WebMvcConfigurerAdapter
, or create bean of WebMvcConfigurer
.
2. Spring Security
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll() //Permits your preflight request
}
This enables all methods, all paths and origins. So, use with caution and only in development. Works as on Spring Boot 2.3.3.RELEASE
Upvotes: 3
Reputation: 51
This ALLOWS ANY origin WITH CREDENTIALS for CORS:
@Component
public class FilterChainConfig implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (servletResponse instanceof HttpServletResponse){
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
String requestOrigin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", requestOrigin);
response.setHeader("Access-Control-Allow-Credentials", "true");
//response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS, HEAD");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
filterChain.doFilter(request, response);
}
}
}
Upvotes: 0
Reputation: 1942
In my case, I just added this class and use @EnableAutConfiguration
:
@Component
public class SimpleCORSFilter extends GenericFilterBean {
/**
* The Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
logger.info("> doFilter");
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
//response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, resp);
logger.info("< doFilter");
}
}
Upvotes: 4
Reputation: 3202
According the CORS filter documentation:
"Spring MVC provides fine-grained support for CORS configuration through annotations on controllers. However when used with Spring Security it is advisable to rely on the built-in CorsFilter that must be ordered ahead of Spring Security’s chain of filters"
Something like this will allow GET
access to the /ajaxUri
:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AjaxCorsFilter extends CorsFilter {
public AjaxCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration config = new CorsConfiguration();
// origins
config.addAllowedOrigin("*");
// when using ajax: withCredentials: true, we require exact origin match
config.setAllowCredentials(true);
// headers
config.addAllowedHeader("x-requested-with");
// methods
config.addAllowedMethod(HttpMethod.OPTIONS);
config.addAllowedMethod(HttpMethod.GET);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/startAsyncAuthorize", config);
source.registerCorsConfiguration("/ajaxUri", config);
return source;
}
}
Of course, your SpringSecurity configuration must allow access to the URI with the listed methods. See @Hendy Irawan answer.
Upvotes: 6
Reputation: 1
I had a similar problem but with the specific requirement to have the CORS header set from decorators in our endpoints, like this:
@CrossOrigin(origins = "*", allowCredentials = "true")
@PostMapping(value = "/login")
Or
@CrossOrigin(origins = "*")
@GetMapping(value = "/verificationState")
So simply intercepting the request, setting the CORS header manually and sending 200 back was not an option, because allowCredentials was needed to be true in some cases and wildcards are not allowed then. Sure, a CORS registry would have helped, but since our clients are angular in capacitor on android and iOS, there is no specific domain to register. So the clean way to do - in my opinion - is to pipe preflights directly to the endpoints to let them handle it. I solved it with this:
@Component
public class PreflightFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(PreflightFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
if (CorsUtils.isPreFlightRequest(request)) {
logger.info("Preflight request accepted");
SecurityContextHolder.getContext().setAuthentication(createPreflightToken(request));
}
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken createPreflightToken(HttpServletRequest request) {
UserDetails userDetails = new User("Preflight", "",
true, true, true, true,
Stream.of(new SimpleGrantedAuthority("AppUser")).collect(Collectors.toSet()));
UsernamePasswordAuthenticationToken preflightToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
preflightToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
return preflightToken;
}
}
Keep in mind that the endpoint decorators don't work like wildcards here as one would expect!
Upvotes: 0
Reputation: 61
With SpringBoot 2 Spring Security, The code below perfectly resolved Cors issues
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*")); // <-- you may change "*"
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList(
"Accept", "Origin", "Content-Type", "Depth", "User-Agent", "If-Modified-Since,",
"Cache-Control", "Authorization", "X-Req", "X-File-Size", "X-Requested-With", "X-File-Name"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistrationBean() {
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(corsConfigurationSource()));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
Then for the WebSecurity Configuration, I added this
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/oauth/tokeen").permitAll()
.antMatchers(HttpMethod.GET, "/").permitAll()
.antMatchers(HttpMethod.POST, "/").permitAll()
.antMatchers(HttpMethod.PUT, "/").permitAll()
.antMatchers(HttpMethod.DELETE, "/**").permitAll()
.antMatchers(HttpMethod.OPTIONS, "*").permitAll()
.anyRequest().authenticated()
.and().cors().configurationSource(corsConfigurationSource());
}
Upvotes: 3
Reputation: 1089
Ok, after over 2 days of searching we finally fixed the problem. We deleted all our filter and configurations and instead used this 5 lines of code in the application class.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
final ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
};
}
}
Upvotes: 32
Reputation:
Class WebMvcConfigurerAdapter
is deprecated as of 5.0 WebMvcConfigurer
has default methods and can be implemented directly without the need for this adapter. For this case:
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
}
See also: Same-Site flag for session cookie
Upvotes: 8
Reputation: 151
This solution unlock me after couple of hours of research :
In the configuration initialize the core() option
@Override
public void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.etc
}
Initialize your Credential, Origin, Header and Method as your wish in the corsFilter.
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new
UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
I didn't need to use this class:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
}
Upvotes: 7
Reputation: 915
There's 8 hours of my life I will never get back...
Make sure that you set both Exposed Headers AND Allowed Headers in your CorsConfiguration
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.setExposedHeaders(Arrays.asList("Authorization", "content-type"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "content-type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Upvotes: 18
Reputation: 17990
With Spring Security in Spring Boot 2 to configure CORS globally (e.g. enabled all request for development) you can do:
@Bean
protected CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().authorizeRequests()
.anyRequest().permitAll()
.and().csrf().disable();
}
Upvotes: 16
Reputation: 356
Since i had problems with the other solutions (especially to get it working in all browsers, for example edge doesn't recognize "*" as a valid value for "Access-Control-Allow-Methods"), i had to use a custom filter component, which in the end worked for me and did exactly what i wanted to achieve.
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods",
"ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Key, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {
// not needed
}
public void destroy() {
//not needed
}
}
Upvotes: 31
Reputation: 1006
You don't need:
@Configuration
@ComponentScan("com.company.praktikant")
@EnableWebSecurity
already has @Configuration
in it, and I cannot imagine why you put @ComponentScan
there.
About CORS filter, I would just put this:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
Into SecurityConfiguration class and remove configure and configure global methods. You don't need to set allowde orgins, headers and methods twice. Especially if you put different properties in filter and spring security config :)
According to above, your "MyFilter" class is redundant.
You can also remove those:
final AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CORSConfig.class);
annotationConfigApplicationContext.refresh();
From Application class.
At the end small advice - not connected to the question. You don't want to put verbs in URI. Instead of http://localhost:8080/getKunden
you should use HTTP GET method on http://localhost:8080/kunden
resource. You can learn about best practices for design RESTful api here: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
Upvotes: 11
Reputation: 139
In many places, I see the answer that needs to add this code:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
but in my case, it throws an unexpected class type exception. corsFilter()
bean requires CorsFilter
type, so I have done this changes and put this definition of bean in my config and all is OK now.
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
Upvotes: 5
Reputation: 21384
Since Spring Security 4.1, this is the proper way to make Spring Security support CORS (also needed in Spring Boot 1.4/1.5):
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
}
and:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.csrf().disable();
http.cors();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Do not do any of below, which are the wrong way to attempt solving the problem:
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
web.ignoring().antMatchers(HttpMethod.OPTIONS);
Reference: http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html
Upvotes: 126