Thursday, March 17, 2016

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

Leave a Comment

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() {     }  } 

3 Answers

Answers 1

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() {}  } 

Answers 2

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

Answers 3

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment