CORS Filter before Authentication Filter - is less secure? Spring Security Filter Chain Order - angularjs

I found that while accessing ReST services from single-page applications that in order to properly allow access to ReST endpoints I had to register a CORS filter before my authentication filter. Is this less secure or a poor security practice?
My security configuration now looks like
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Inject
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/health","/metrics", "/v1/users/register", "/swagger-ui/**", "/v2/api-docs").permitAll()
.antMatchers("/mappings", "/v1/**", "/backend-service/**").authenticated()
.and()
.httpBasic()
.realmName("serviceGateway")
.and()
.csrf()
.disable()
.headers()
.frameOptions().disable()
.and().addFilterBefore(new SimpleCORSFilter(), ChannelProcessingFilter.class);
}
}
And my SimpleCORSFilter looks like
public class SimpleCORSFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* This method adds specific headers to the HTTP request to enable CORS
* requests
* #param request
* #param response
* #param chain
* #throws IOException
* #throws ServletException
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, x-requested-with, Cache-Control");
chain.doFilter(request, res);
}
#Override
public void destroy() {
}
}
I access the code with a simple $http call in Angular
$scope.login = function() {
$http({
method: 'GET',
url: 'https://myservice.mydomain.com:8095/v1/users/login',
headers: {
'Authorization': 'Basic ' + btoa("username:password")
}
})
.then(successCallback);
};
I am thinking that putting the CORS filter before security only means that the CORS headers will be added to every request, which doesn't seem like much of a security hole since I send no sensitive data in headers, excepting the Authorization header.
Am I thinking right here or is there something I am not seeing?

I think this is perfectly fine. In fact when your JavaScript code posts to a resource in another origin, the browser will issue a pre-flight request (OPTIONS verb) without the authorization header.
If your authentication code runs before the CORS handler, it has to make an exception for this request, to avoid returning 401 Unauthorized on the pre-flight.

Related

CORS not working with Spring Boot and Spring Cloud without Spring Security

I am using Spring Boot 2.2.4.RELEASE with Spring Cloud Hoxton.SR1 and without Spring Security, In that GET method is working fine but POST & PUT methods are not working.
#Configuration
#Order(value = Integer.MAX_VALUE)
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5500")
.allowedHeaders("*")
.allowedMethods("POST", "PUT", "DELETE", "HEAD");
}
}
#Component
public class SimpleCORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, response);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
AngularJS Code
$http({
method: 'POST',
url: 'http://b28c-103-85-11-107.ngrok.io/game/brand-styles',
data: {
"fontColour": "FFFFFF",
"backgroundColour": "006400",
"displayType": 1,
"buttonColour": "FFC314"
}
})
.then(function (response) { $scope.data = data; })
.catch(function (err) { console.log(err) });
I have tried multiple ways to solve the issue as suggested on same platform in different questions but no one worked for me.
Access to XMLHttpRequest at
'http://b28c-103-85-11-107.ngrok.io/game/brand-styles' from origin
'http://localhost:5500' 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.
POST http://b28c-103-85-11-107.ngrok.io/game/brand-styles
net::ERR_FAILED
The possible reason behind the issue in your case would be due to the following statement that you've mentioned in the SimpleCORSFilter class.
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
Looks like Origin header is dropped before reaching to your local server or may be dropped by the local server itself. You can try with the following change to verify your case.
response.setHeader("Access-Control-Allow-Origin", "http://localhost:5500");

Struggling with CORS error using Spring,Angularjs and Ionic frame work

Controller.java
In Controller class,I have defined url and while accessing from browser its working fine.
But when accessing the same url request from Ionic program, getting CORS error.Due to this error i have added necessary content in doFilter method too.But still left helpless.
#RestController
#RequestMapping("/service")
public class Controller implements Filter {
#RequestMapping(value = "/name", method = RequestMethod.POST,
headers = "content-type=application/x-www-form-urlencoded",produces="application/json")
public String reg(#ModelAttribute Farmer farmer) {
System.out.println("Getting request from Mobile client...!!" + farmer);//farmer.firstName is null
String result = "Hello..!";
System.out.println("Request processed");
return result;
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
System.out.println("External request start..!!");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT,GET,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, resp);
System.out.println("External request end..!!");
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
Farmer.java
public class Farmer {
private String firstName;
private String lastName;
//getters and setters
}
I have edited my question.Please do check it.
Thank you.
If you use chrome you must start it with the flag --disable-web-security or install the extension Allow-Control-Allow-Origin: *.
It's not a code problem, when you build your app with cordova or phonegap build the error message will not be throw.
Here is how I would do it, add this to a class annotated with component or configuration:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/service/**").allowedOrigins("*").allowedMethods("GET", "POST","PUT", "DELETE");
}
};
}
After going with lot of trials and referring examples.Finally fixed this issue.So just thought of adding here.If in case anyone might need it.
This fixes just by adding
#CrossOrigin,#RestController,consumes="application/json" in your
controller method.
#CrossOrigin
#RestController
#RequestMapping("/service")
public class Controller implements Filter {
#RequestMapping(value = "/name", method = RequestMethod.POST,
headers = "content-type=application/x-www-form-urlencoded",consumes="application/json")
public String reg(#ModelAttribute Farmer farmer) {
System.out.println("Getting request from Mobile client...!!" + farmer);//farmer.firstName is null
String result = "Hello..!";
System.out.println("Request processed");
return result;
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
System.out.println("External request start..!!");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT,GET,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, resp);
System.out.println("External request end..!!");
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
Thank you

Response for preflight has invalid HTTP status code 403

I am using as Server-side Spring-boot and providing a dummy service for test
where my ServiceCaller.java=
package com.user.server.mfw;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.handler.MappedInterceptor;
#RestController
public class ServiceCaller {
#CrossOrigin(allowedHeaders="*",allowCredentials="true")
#RequestMapping(value="/serviceCaller",method=RequestMethod.POST, headers="content-type=text/*")
#ResponseBody
String serviceListener(#RequestParam("serviceName") String serviceName,HttpSession session,HttpServletRequest theHttpServletReq ) throws IOException
{
if(!serviceName.isEmpty())
{
byte[] encoded = Files.readAllBytes(Paths.get("C://Users//something//Desktop//asd.json"));
return new String(encoded, "UTF-8");
}
return "gelemedi";
}
private void checkActiveSessionControl(HttpSession session)
{
System.out.println("Session Id:" + session.getId() +" // " + session.getCreationTime());
if(session == null)
System.out.println("Null");
else if(session.isNew())
System.out.println("New");
else
System.out.println("Old");
}
}
where my client-side is a ionic framework and based on angular.js...
Controller.js
$scope.getInfo = function() {
$http({
url: SERVER_ENDPOINT.url + '/serviceCaller',
method: 'POST',
params: {serviceName: 'deneme'},
withCredentials: true
}).then(function(result) {
var alertPopup = $ionicPopup.alert({
title: 'ALOHA!',
template: 'dksjd ' + result
});
$scope.memberInfo = result.data.accountNumber;
}, function() {
var alertPopup = $ionicPopup.alert({
title: ' failed!',
template: 'da'
});
}
);
};
Basically I get a "invalid HTTP status code 403" when I use POST method instead of GET. However I would like to use POST for calling instead of GET.
However I could not figure out where I am making a mistake....
any solution will be appreciated!
If your browser is sending a pre-flight OPTIONS request , all you have to do is to allow that in your WebSecurity configuration by allowing http OPTIONS.
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
I think you're not passing any parameter using this anotation:
#CrossOrigin(allowedHeaders="*",allowCredentials="true")
#RequestMapping(value="/serviceCaller",method=RequestMethod.POST, headers="content-type=text/*")
#ResponseBody
String serviceListener(#RequestParam("serviceName") String serviceName,HttpSession session,HttpServletRequest theHttpServletReq ) throws IOException
{
you should replace value="/serviceCaller" by value="/{serviceCaller}"
EDIT
please add this class to your project to solve the CORS problems
#Component
public class SimpleCORSFilter implements Filter {
#Override
public void init(FilterConfig fc) throws ServletException {}
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, resp);
}
#Override
public void destroy() {}
}
As shown in the AngularJS docs
XSRF is a technique by which an unauthorized site can gain your user's private data. Angular provides a mechanism to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain could read the cookie, your server can be assured that the XHR came from JavaScript running on your domain. The header will not be set for cross-domain requests.
so the default header is x-xsrf-token.
Add this filter in your websecurityconfiguration after CsrfFilter
public class CsrfHeaderFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
add the filter as shown here:
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()...
.and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
}
}
I found the explanation of preflight request very clear in answer to question Angularjs Post not sending headers to Spring JWT.
Since you are using Spring Security, you have to enable CORS at Spring Security level as well to allow it to leverage the configuration defined at Spring MVC level as:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
Here is very excellent tutorial explaining CORS support in Spring MVC framework.
This enables HttpMethod.Options request to include headers in preflight request.

No 'Access-Control-Allow-Origin' header is present on the requested resource. Ionic, AngularJS, Spring Boot 1.3

I am using Ionic and Spring Boot 1.3. It wasn't until I upgraded to 1.3 that I am getting this problem...
Apparently after updating to Spring Boot 1.3. CorsFilter is being ignored completely. All this deprecation is driving me nuts. So I looked up the NEW way and this is what I got.
package app.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://192.168.1.66:8101")
.allowCredentials(false)
.maxAge(3600)
.allowedHeaders("Accept", "Content-Type", "Origin", "Authorization", "X-Auth-Token")
.exposedHeaders("X-Auth-Token", "Authorization")
.allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
}
}
The above piece of code is excuted on the boot of the application. Unlike CorsFilter that is executed every time there is a request. But switching to Spring Boot 1.3, I can no longer get this in the chain filter.
Again, the code is being loaded, I set a break point and addCorsMapping is called every time so the settings are being made. So.... Why am I still getting this error
XMLHttpRequest cannot load http://192.168.1.66:8080/login?username=billyjoe&password=happy. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.1.66:8101' is therefore not allowed access.
EDIT
Below is my old CorsFilter. It no longer works since I updated to Spring Boot 1.3
package app.config;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
#Component
public class CorsFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(CorsFilter.class);
public CorsFilter() {
log.info("SimpleCORSFilter init");
}
#Override
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String clientOrigin = request.getHeader("origin");
response.addHeader("Access-Control-Allow-Origin", clientOrigin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Origin, Authorization, X-Auth-Token");
response.addHeader("Access-Control-Expose-Headers", "X-Auth-Token");
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(request, response);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
You can try something like this. It's working for me:.
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
Figured it out. I am using a CustomToken Login and for some reason The new Configurations for 1.3 and higher do not set the response with Access-Control-Allow-Origin when using custom Login Authentication. So somewhere in my custom login I had to add the response header.
httpServletResponse.addHeader("Access-Control-Allow-Origin", "http://192.168.1.66:8080");
In older versions of Spring, the CorsFilter is set in the filter so it would set this everytime a call is made. It seems the New Configs only work when properly calling a Controller but since login is handled in the Filters and not a Controller, the response body is never set. It properly authenticates the user Access-Control-Allow-Origin
In a my open source project I needed of CORS support befor the update to Spring 4.2 I used a filter like this:
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
as the answare of Raca. However when I update at spring-boot 1.3.3 I changed the configuration as below:
#SpringBootApplication
#Configuration
#EnableEurekaClient
#RibbonClients
#EnableCircuitBreaker
#EnableZuulProxy
#EnableJpaRepositories(basePackages = "it.valeriovaudi.documentlibrary.repository")
#EnableTransactionManagement
#EnableRedisHttpSession
#PropertySource("classpath:restBaseUrl.properties")
#EnableAspectJAutoProxy(proxyTargetClass = true) // without this declaration the RestTemplate injection wil be fails becouse spring cloud proxied this class for load balance with netflix ribbon
public class UserDocumentLibraryClientApplication {
public static void main(String[] args) {
SpringApplication.run(UserDocumentLibraryClientApplication.class, args);
}
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurerSupport() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public EmbeddedServletContainerCustomizer exceptionHandling() {
return container -> container.addErrorPages(new ErrorPage("/exception"));
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
this is taken from the main configuration of my project and this kind of configuration works well for me even in a complex distributed system with netflix api of Spring cloud.
I hope that this can help you.

CORS with spring-boot and angularjs not working

I am trying to call REST endpoints on one application (spring-boot application) from another (angularjs). The applications are running on the following hosts and ports.
REST application, using spring boot, http://localhost:8080
HTML application, using angularjs, http://localhost:50029
I am also using spring-security with the spring-boot application. From the HTML application, I can authenticate to the REST application, but, thereafter, I still cannot access any REST endpoint. For example, I have an angularjs service defined as follows.
adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
var s = {};
s.isAdminLoggedIn = function(data) {
return $http({
method: 'GET',
url: 'http://localhost:8080/api/admin/isloggedin',
withCredentials: true,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
};
s.login = function(username, password) {
var u = 'username=' + encodeURI(username);
var p = 'password=' + encodeURI(password);
var r = 'remember_me=1';
var data = u + '&' + p + '&' + r;
return $http({
method: 'POST',
url: 'http://localhost:8080/login',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
return s;
}]);
The angularjs controller looks like the following.
adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
$scope.username = '';
$scope.password = '';
$scope.signIn = function() {
AdminService.login($scope.username, $scope.password)
.success(function(d,s) {
if(d['success']) {
console.log('ok authenticated, call another REST endpoint');
AdminService.isAdminLoggedIn()
.success(function(d,s) {
console.log('i can access a protected REST endpoint after logging in');
})
.error(function(d, s) {
console.log('huh, error checking to see if admin is logged in');
$scope.reset();
});
} else {
console.log('bad credentials?');
}
})
.error(function(d, s) {
console.log('huh, error happened!');
});
};
}]);
On the call to http://localhost:8080/api/admin/isloggedin, I get a 401 Unauthorized.
On the REST application side, I have a CORS filter that looks like the following.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
#Override
public void destroy() { }
#Override
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", "http://localhost:50029");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig config) throws ServletException { }
}
My spring security configuration looks like the following.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
private JsonAuthSuccessHandler jsonAuthSuccessHandler;
#Autowired
private JsonAuthFailureHandler jsonAuthFailureHandler;
#Autowired
private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PersistentTokenRepository persistentTokenRepository;
#Value("${rememberme.key}")
private String rememberMeKey;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(jsonAuthSuccessHandler)
.failureHandler(jsonAuthFailureHandler)
.permitAll()
.and()
.logout()
.deleteCookies("remember-me", "JSESSIONID")
.logoutSuccessHandler(jsonLogoutSuccessHandler)
.permitAll()
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(persistentTokenRepository)
.rememberMeCookieName("REMEMBER_ME")
.rememberMeParameter("remember_me")
.tokenValiditySeconds(1209600)
.useSecureCookie(false)
.key(rememberMeKey);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
}
All the handlers are doing is writing out a JSON response like {success: true} based on if the user logged in, failed to authenticate, or logged out. The RestAuthenticationEntryPoint looks like the following.
#Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
throws IOException, ServletException {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
Any ideas on what I am missing or doing wrong?
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
#Component
public class SimpleCORSFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
public SimpleCORSFilter() {
log.info("SimpleCORSFilter init");
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
No need extra define this filter just add this class. Spring will be scan and add it for you. SimpleCORSFilter.
Here is the example: spring-enable-cors
I had been into the similar situation. After doing research and testing, here is my findings:
With Spring Boot, the recommended way to enable global CORS is to declare within Spring MVC and combined with fine-grained #CrossOrigin configuration as:
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
}
Now, since you are using Spring Security, you have to enable CORS at Spring Security level as well to allow it to leverage the configuration defined at Spring MVC level as:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
Here is very excellent tutorial explaining CORS support in Spring MVC framework.
UPDATE (Sep 13, 2022):
With latest version of Spring 5 and above, you have to use WebMvcConfigurer as below:
#EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
}
}
If you want to enable CORS without using filters or without config file just add
#CrossOrigin
to the top of your controller and it work.
To build on other answers above, in case you have a Spring boot REST service application (not Spring MVC) with Spring security, then enabling CORS via Spring security is enough (if you use Spring MVC then using a WebMvcConfigurer bean as mentioned by Yogen could be the way to go as Spring security will delegate to the CORS definition mentioned therein)
So you need to have a security config that does the following:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//other http security config
http.cors().configurationSource(corsConfigurationSource());
}
//This can be customized as required
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
List<String> allowOrigins = Arrays.asList("*");
configuration.setAllowedOrigins(allowOrigins);
configuration.setAllowedMethods(singletonList("*"));
configuration.setAllowedHeaders(singletonList("*"));
//in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
This link has more information on the same: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors
Note:
Enabling CORS for all origins (*) for a prod deployed application may not always be a good idea.
CSRF can be enabled via the Spring HttpSecurity customization without any issues
In case you have authentication enabled in the app with Spring (via a UserDetailsService for example) then the configuration.setAllowCredentials(true); must be added
Tested for Spring boot 2.0.0.RELEASE (i.e., Spring 5.0.4.RELEASE and Spring security 5.0.3.RELEASE)
Im using spring boot 2.1.0 and what worked for me was to
A. Add cors mappings by:
#Configuration
public class Config implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
}
B. Add below configuration to my HttpSecurity for spring security
.cors().configurationSource(new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
})
Also in case of a Zuul proxy you can use this INSTEAD OF A and B (just use HttpSecurity.cors() to enable it in Spring security):
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
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);
}
This works for me:
#Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {
//...
#Override
protected void configure(HttpSecurity http) throws Exception {
//...
http.cors().configurationSource(new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
});
//...
}
//...
}
This is what worked for me.
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
}
}
#Configuration
public class WebConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedMethods("*")
.allowedHeaders("*")
.allowedOrigins("*")
.allowCredentials(true);
}
}
For me the only thing that worked 100% when spring security is used was to skip all the additional fluff of extra filters and beans and whatever indirect "magic" people kept suggesting that worked for them but not for me.
Instead just force it to write the headers you need with a plain StaticHeadersWriter:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// your security config here
.authorizeRequests()
.antMatchers(HttpMethod.TRACE, "/**").denyAll()
.antMatchers("/admin/**").authenticated()
.anyRequest().permitAll()
.and().httpBasic()
.and().headers().frameOptions().disable()
.and().csrf().disable()
.headers()
// the headers you want here. This solved all my CORS problems!
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Max-Age", "3600"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization"));
}
}
This is the most direct and explicit way I found to do it. Hope it helps someone.
Step 1
By annotating the controller with #CrossOrigin annotation will allow the CORS configurations.
#CrossOrigin
#RestController
public class SampleController {
.....
}
Step 2
Spring already has a CorsFilter even though You can just register your own CorsFilter as a bean to provide your own configuration as follows.
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Provide list of origins if you want multiple origins
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
If originally your program doesn't use spring security and can't afford for a code change, creating a simple reverse proxy can do the trick. In my case, I used Nginx with the following configuration:
http {
server {
listen 9090;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
proxy_pass http://localhost:8080;
}
}
}
My program listens to :8080.
REF: CORS on Nginx
In our Spring Boot app, we have set up CorsConfigurationSource like this.
Sequence of adding allowedOrigns first and then setting applyPermitDefaultValues() let Spring set up default values for allowed headers, exposed headers, allowed methods, etc. so we don't have to specify those.
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8084"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**", configuration);
return configurationSource;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.access("#authProvider.validateApiKey(request)")
.anyRequest().authenticated()
.and().cors()
.and().csrf().disable()
.httpBasic().authenticationEntryPoint(authenticationEntryPoint);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
check this one:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
...
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
...
}
Extending WebSecurityConfigurerAdapter class and overriding configure() method in your #EnableWebSecurity class would work : Below is sample class
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling();
http.headers().cacheControl();
#Override
public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) {
return new CorsConfiguration().applyPermitDefaultValues();
}
});
}
}
This answer copies the #abosancic answer but adds extra safety to avoid CORS exploit.
Tip 1: Do not reflect the incoming Origin as is without checking the list of allowed hosts to access.
Tip 2: Allow credentialed request only for whitelisted hosts.
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
#Component
public class SimpleCORSFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
private List<String> allowedOrigins;
public SimpleCORSFilter() {
log.info("SimpleCORSFilter init");
allowedOrigins = new ArrayList<>();
allowedOrigins.add("https://mysafeorigin.com");
allowedOrigins.add("https://itrustthissite.com");
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String allowedOrigin = getOriginToAllow(request.getHeader("Origin"));
if(allowedOrigin != null) {
response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
response.setHeader("Access-Control-Allow-Credentials", "true");
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
public String getOriginToAllow(String incomingOrigin) {
if(allowedOrigins.contains(incomingOrigin.toLowerCase())) {
return incomingOrigin;
} else {
return null;
}
}
}
Just Make a single class like, everything will be fine with this:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCorsConfig implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype");
response.setHeader("Access-Control-Max-Age", "3600");
if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig config) throws ServletException {
}
}
This is what has worked for me in order to disable CORS between Spring boot and React
#Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* Overriding the CORS configuration to exposed required header for ussd to work
*
* #param registry CorsRegistry
*/
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(4800);
}
}
I had to modify the Security configuration also like below:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors().configurationSource(new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
}).and()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler());
}
I was suprised to only find Eduardo Dennis pointing to the up-to-date solution which is much simpler & doesn't involve the need to write your own Filter classes: It's using the
org.springframework.web.bind.annotation.CrossOrigin annotation on your Controllers
and including and().cors() to your Spring Security configuration.
That's all you have to do!
You can use the #CrossOrigin annotation like this:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("/api")
#CrossOrigin
public class BackendController {
...
}
If you want to configure allowedHeaders, methods, origins and so on, you can simply add those values to the annotation like this: #CrossOrigin(origins = "http://localhost:50029", maxAge = 3600).
Using the #CrossOrigin annotation, the Spring Security configuration becomes extremely easy. Simply add and().cors() to your WebSecurityConfig.java class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.and().cors()
...
}
That's all! You may delete your Filter/CORSFilter classes. If you want to add a global configuration, you can declare a CorsConfigurationSource also. See this great answer or this blog post by Sébastien Deleuze). There's also clearly stated by the Spring developers:
This approach supersedes the filter-based approach previously
recommended.
Therefore the accepted answer is outdated. Here's also a fully working example project: https://github.com/jonashackt/microservice-api-spring-boot
To enable CORS Globally you need to make changes in two places:
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
}
Works as on Spring Boot 2.3.3.RELEASE
The simple way is to create a bean in your spring boot application class(class with #SpringBootApplication) as below:
Note! i specified "http://localhost:4200" below on "setAllowedOrigins()" because am running the application on localhost and using angular default port.
#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);
}
package tiny.url.urlshortner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#SpringBootApplication
public class UrlshortnerApplication {
public static void main(String[] args) {
SpringApplication.run(UrlshortnerApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
}
You can use this annotation on every restController class in sprıng boot
#CrossOrigin("*")
if you are using spring security you need to use this on any class with extended extends WebSecurityConfigurerAdapter
#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;
}

Resources