2

I have this WebMvcConfigurer which works totally fine when deployed over the server. But when I try to send a request from my locally served Angular project to the server, I get the following error.

Access to XMLHttpRequest at 'https://sub.domain.com/api/staff/logout' from origin 'http://localhost:4200' 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.

My Config is as follows:

@Configuration
@EnableWebMvc
public class WebMvcConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedOrigins("*")
                        .allowedHeaders("*")
                        .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
                        .allowCredentials(true).maxAge(3600);
            }

            /**
             * To add our interceptor into Spring configuration, we need to override
             * addInterceptors() method WebMvcConfig class that implements WebMvcConfigurer.
             */
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(new AppInterceptor());
            }
        };
    }
}

I have referred to other questions my didn't find anything that solved my problem. Thanks in advance.

Keshavram Kuduwa
  • 942
  • 10
  • 40
  • "Response to preflight request doesn't pass access control check" --> shouldn't you add `OPTIONS` to the allowed methods then? – Mena Apr 22 '21 at 08:12
  • @Mena Did that, same error. – Keshavram Kuduwa Apr 22 '21 at 08:18
  • Unlucky shot then. Maybe you can analyze the problematic request via your browser's tool kit (e.g. tamper with it) in order to see the headers etc. Might be a nudge in the right direction... – Mena Apr 22 '21 at 08:22

2 Answers2

0

In your Angular application you can add a proxy.config.json that will solve the CORS issue for you locally. This configuration only affects when serving the app locally, so nothing will change on production.

{
    "/api/*": {
      "target": "http://localhost:8080",
      "secure": false,
      "logLevel": "debug",
      "changeOrigin": false
    }
}

Also, see this answer: https://stackoverflow.com/a/47537203/9698467 and the Angular documentation: https://angular.io/guide/build#proxying-to-a-backend-server

The idea is that even though the front-end and the back-end are served on localhost, there is a local server that serves the Angular app and a local server that serves your backend. They are both served on different ports, which causes a cross-origin issue. By using proxy you are effectively routing your Angular backend requests to localhost:8080, thus from Angular's client point of view, everything seems to be on the same origin.

Stefan Zhelyazkov
  • 2,599
  • 4
  • 16
  • 41
  • I am trying to send a request to the server from localhost:4200, I tried your solution with { "/api/*": { "target": "https://sub.domain.com/api", "secure": true, "logLevel": "debug", "changeOrigin": false } } but it isn't working. – Keshavram Kuduwa Apr 22 '21 at 08:49
  • First, make sure that you understand all the parameters from the documentation. `/api/*` might not be the same in your case. Also, make sure your `target` is correct too. You _may_ also need to do a path-rewrite: https://angular.io/guide/build#rewrite-the-url-path These are all explained well in the documentation. – Stefan Zhelyazkov Apr 22 '21 at 08:53
-2

As I'll be implementing Spring Security in the future, and though the question says without Spring Security, I solved this issue by adding Spring Security to the project,

The starter dependency:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

The Configuration Class:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;

import java.util.List;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(
                List.of("Authorization", "Cache-Control", "Content-Type", "X-PT-SESSION-ID", "NGSW-BYPASS"));
        corsConfiguration.setAllowedOrigins(List.of("*"));
        corsConfiguration
                .setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT", "OPTIONS", "PATCH", "DELETE"));
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setExposedHeaders(List.of("Authorization"));

        http.authorizeRequests().antMatchers("/**").permitAll().anyRequest().authenticated().and().csrf().disable()
                .cors().configurationSource(request -> corsConfiguration);

    }
}

I referred this answer, and there are other answers that might be helpful to others as well. Do check it out.

Keshavram Kuduwa
  • 942
  • 10
  • 40
  • 1
    It needs to be clear that when you bypass CORS globally as in this answer, then CORS will be bypassed in all environments - dev and prod. If you only experience CORS locally, then it makes sense to address it only in the local environment. – Stefan Zhelyazkov Apr 22 '21 at 10:28
  • 1
    @StefanZhelyazkov You're right, I'll work more on the proxy part and try to resolve this locally. – Keshavram Kuduwa Apr 22 '21 at 10:53