4

I'm using Java Spring 3.0.4 (can't upgrade due to some requirements) and I need to enable Cors in order for my front-end to talk to my back-end.

My back-end is an angular application running on: http://localhost:4200/home

I have tried the following with no luck:

public static final String CREDENTIALS_NAME = "Access-Control-Allow-Credentials";
public static final String ORIGIN_NAME = "Access-Control-Allow-Origin";
public static final String METHODS_NAME = "Access-Control-Allow-Methods";
public static final String HEADERS_NAME = "Access-Control-Allow-Headers";
public static final String MAX_AGE_NAME = "Access-Control-Max-Age";

@PreAuthorize("hasRole('ADMIN')")
@RequestMapping(value="/data", method=RequestMethod.GET)
public void serverSide(Model model,  HttpServletRequest request, HttpServletResponse response) throws IOException{

    response.setContentType("application/json");
    response.setHeader("Cache-Control", "no-store");

    response.setHeader(CREDENTIALS_NAME, "true");
    response.setHeader(ORIGIN_NAME, "http://localhost:4200");
    response.setHeader(METHODS_NAME, "GET, OPTIONS, POST, PUT, DELETE");
    response.setHeader(HEADERS_NAME, "Origin, X-Requested-With, Content-Type, Accept");
    response.setHeader(MAX_AGE_NAME, "3600");

    PrintWriter out = response.getWriter();

    out.print("TEST!!");
}       
sbattou
  • 319
  • 3
  • 18
  • Have you tried adding `@CrossOrigin` on the controller method? – Madhu Bhat Mar 26 '19 at 17:39
  • I believe that annotation was added in Spring 3.2 but yes I have tried it and it complains that the annotation does not have a definition. @MadhuBhat – sbattou Mar 26 '19 at 17:43
  • Are you by any chance running Apache Tomcat? How are you deploying your app? – Karol Dowbecki Mar 26 '19 at 17:43
  • @KarolDowbecki yes I am running Apache Tomcat but I'm not too sure how our apps are deployed (very new to this team) – sbattou Mar 26 '19 at 17:46
  • @sbattou can you try with any of the answers here https://stackoverflow.com/questions/32319396/cors-with-spring-boot-and-angularjs-not-working ? – Madhu Bhat Mar 26 '19 at 17:51
  • @MadhuBhat Those answers would work on more recent versions of Spring. I tried and no luck – sbattou Mar 26 '19 at 18:07
  • @sbattou answer with `Filter` should work. If you remove `@Component` annotation. You will also need to add corresponding entries into `web.xml` – Ivan Mar 26 '19 at 18:45
  • @Ivan could you provide a code example? Not too sure what you mean by adding corresponding entries into web.xml – sbattou Mar 26 '19 at 19:33

3 Answers3

6

You can extends Filter interface.

public class CORSFilter implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {

  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      HttpServletResponse httpResponse = (HttpServletResponse) response;
      httpResponse.addHeader("Access-Control-Allow-Origin", "*");
      httpResponse.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, OPTIONS");
      httpResponse.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");       chain.doFilter(request, response);
  }

  @Override
  public void destroy() {

  }
}

And then you need to register filter in web.xml

<filter>
    <filter-name>cors</filter-name>
    <filter-class>com.yourpackage.CORSFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>cors</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Ivan
  • 8,508
  • 2
  • 19
  • 30
  • I really appreciate it, do I have to call the CorsFilter class from my controllers or will the web.xml file basically apply it for any CRUD operation? – sbattou Mar 27 '19 at 00:14
  • It should apply to every URL in that web app since filter is mapped to `/*` URL. – Ivan Mar 27 '19 at 00:19
  • Still getiing the error SEC7120: Origin http://localhost:4200 not found in Access-Control-Allow-Origin header. I really thought this would work, any other suggestions? – sbattou Mar 27 '19 at 12:40
  • Try to replace `"Access-Control-Allow-Origin", "*"` with `"Access-Control-Allow-Origin", "http://localhost:4200"` – Ivan Mar 27 '19 at 13:01
  • It turns out there was a piece of code that was redirecting my request, as soon as I disabled it everything worked! – sbattou Mar 27 '19 at 14:33
  • I'm curious why you are using `addHeader` for the first two headers and `setHeader` only for `Access-Control-Allow-Headers`? Thanks. – user1491636 Feb 03 '20 at 21:25
2

You can enable CORS by creating an Interceptor. Please follow below steps:

  1. Create a Interceptor by Extending HandlerInterceptorAdapter

    public class CorsInterceptor extends HandlerInterceptorAdapter {
    
        public static final String CREDENTIALS_NAME = "Access-Control-Allow-Credentials";
        public static final String ORIGIN_NAME = "Access-Control-Allow-Origin";
        public static final String METHODS_NAME = "Access-Control-Allow-Methods";
        public static final String HEADERS_NAME = "Access-Control-Allow-Headers";
        public static final String MAX_AGE_NAME = "Access-Control-Max-Age";
    
       @Override
       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
          Object handler) throws Exception {
          response.setHeader(CREDENTIALS_NAME, "true");
          response.setHeader(ORIGIN_NAME, "http://localhost:4200");
          response.setHeader(METHODS_NAME, "GET, OPTIONS, POST, PUT, DELETE");
          response.setHeader(HEADERS_NAME, "Origin, X-Requested-With, Content-Type, 
            Accept");
          response.setHeader(MAX_AGE_NAME, "3600");
          return true;
      }
    
    }
    
  2. Register the above created interceptor on your web configuration.

    public class WebConfig extends WebMvcConfigurerAdapter {
    
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CorsInterceptor());
      }
     // continue if any ..
    }
    
  3. Above works fine for GET requests but for any other modification request (POST, DELETE, PUT), browser will send preflight OPTIONS request which SpringMVC ignores. So, you have to dispatch Options request. You can add dispatchOptionRequest on web.xml as follows:

    <servlet>
        <servlet-name>servletName</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
         <param-name>dispatchOptionsRequest</param-name>
         <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    

Hope this helps! Thanks.

Sushan Baskota
  • 315
  • 3
  • 10
  • Thank you for taking the time to post an answer. Do I create the web configuration class because I don't seem to have one in my application? – sbattou Mar 27 '19 at 00:12
  • I am still using Spring 3.0.5, do I need to add "CorsInterceptor" or "WebConfig" anywhere in the xml file as configuration or Spring will auto load these classes while startup? – arunan Feb 08 '21 at 08:24
0

With WebMVC it is possible and works for me. Try this , but if you use spring security i might need to update the answer

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfiguration implements WebMvcConfigurer {

private static final String HTTP_LOCALHOST_4200 = "http://localhost:4200";
private static final String GET = "GET";
private static final String POST = "POST";
private static final String PUT = "PUT";
private static final String DELETE = "DELETE";
private static final String HEAD = "HEAD";

@Override
public void addCorsMappings(CorsRegistry registry) {

    registry.addMapping("/**")
            .allowedOrigins(
                    HTTP_LOCALHOST_4200).allowedMethods(GET, POST, PUT, DELETE, 
  HEAD).allowCredentials(true);
 }
 }
Shubham
  • 997
  • 1
  • 9
  • 15