简体   繁体   中英

Unable To Make Spring Boot API Request Due To CORS Docker

I have a React frontend app that makes an API call to a Spring boot app.

Both are in separate docker containers. When it's run locally everything is fine, however after deployment, when the call is made, I get a CORS error:

Access to fetch at 'http://xx.xx.xxx.xx:8080/simulations/1/ratings/1' from origin 'http://xx.xx.xxx.xx:3000' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I'm not sure why this is the case. To my mind I've coded up everything to allow CORS access (as I said it works locally, so I don't understand why it fails after deployment. I've read up a bit about docker and localhost but it just seems quite confusing to me at the moment.

This is my Java Security code from WebSecurityConfigurerAdapter :

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://xx.xx.xxx.xx:3000"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

docker-compose.yml is as follows:

version: '3'
services:     
  application-server:
    restart: always
    image: 'myhub/app-server:cors'
    expose:
      - '8080'
    ports:
      - '8080:8080'
    networks:
      - local      
  application-client:
    restart: always
    image: 'myhub/app-client:cors'
    ports:
      - '3000:80'
    stdin_open: true
    depends_on:
      - application-server
    networks:
      - local
networks: 
  local:
    driver: bridge      

And finally the nginx.conf :

http
{
  server_tokens off;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  upstream backend
  {
    server xx.xx.xxx.xx:8080;
  }

  server
  {

    listen 80;
    server_name localhost;

    access_log /var/log/nginx/host.access.log;
    error_log /var/log/nginx/host.error.log;


    root /var/www;
    index index.html index.htm;

    location ~* \.(?:manifest|appcache|html?|xml|json)$
    {
      expires -1;
    }

    location ~* \.(?:css|js)$
    {
      try_files $uri =404;
      expires 1y;
      access_log off;
      add_header Cache-Control "public";
    }

    # Any route containing a file extension (e.g. /devicesfile.js)
    location ~ ^.+\..+$
    {
      try_files $uri =404;
    }

    location /
    {

      root /var/www;
      index index.html;
      autoindex on;
      set $fallback_file /index.html;
      if ($http_accept !~ text/html)
      {
        set $fallback_file /null;
      }
      if ($uri ~ /$)
      {
        set $fallback_file /null;
      }
      try_files $uri $fallback_file;

      if ($request_method = 'OPTIONS')
      {
        add_header 'Access-Control-Allow-Origin: $http_origin');
        add_header 'Access-Control-Allow-Origin: GET, POST, DELETE, PUT, PATCH, OPTIONS');
        add_header 'Access-Control-Allow-Credentials: true');
        add_header 'Vary: Origin');

      }

      add_header 'Access-Control-Allow-Origin' "$http_origin" always;
      add_header 'Access-Control-Allow-Credentials' 'true' always;
      add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
      add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;

    }
  }
}

What do I need to do with the containers to allow CORS access?

First: to benefit from CORS, you don't need to focus on http client configuration.
The authorization is allowed only by the backend that answers to the question: is that host, port, request acceptable? Contrary to CSRF that requires configuration both client and server.

I mention that since you expose your client conf.

In any way, in Spring Boot (backend of course), we enable CORS declaratively from the WebSecurityConfigurerAdapter.configure(HttpSecurity http) method as simply as:

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.cors()...
}

The cors() javadoc states that:

Adds a CorsFilter to be used. If a bean by the name of corsFilter is provided, that CorsFilter is used. Else if corsConfigurationSource is defined, then that CorsConfiguration is used.

So first, check that.

Then you have three options:
– to do no additional thing. In this case, Spring security will use the default class provided by Spring security and the default CorsConfigurationSource bean associated to.
– to declare a bean named corsFilter . In this case, Spring security will use it instead of the default.
– to declare a bean named corsConfigurationSource . In that case, Spring will use the default CorsFilter with the custom corsConfigurationSource declared by the application.

You used the last way.

If it is not enough, you may have something in your WebSecurity configs that prevents the CORS filter to be handled at the right time.
Add that property and take time to analyse what Spring Security does about CORS:

logging.level.org.springframework.security=DEBUG

I wrote that post some months ago. Maybe it could help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM