CORS ze sprężyną i angularjs nie działa

87

Próbuję wywołać punkty końcowe REST w jednej aplikacji (aplikacja rozruchu sprężynowego) z innej (angularjs). Aplikacje działają na następujących hostach i portach.

  • Aplikacja REST za pomocą rozruchu sprężynowego, http://localhost:8080
  • Aplikacja HTML, wykorzystująca angularjs, http://localhost:50029

Używam również spring-securityz aplikacją Spring-Boot. Z aplikacji HTML mogę uwierzytelnić się w aplikacji REST, ale potem nadal nie mogę uzyskać dostępu do żadnego punktu końcowego REST. Na przykład mam usługę angularjs zdefiniowaną w następujący sposób.

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;
}]);

Kontroler angularjs wygląda następująco.

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!');
            });
    };
}]);

Podczas rozmowy telefonicznej http://localhost:8080/api/admin/isloggedinotrzymuję 401 Unauthorized.

Po stronie aplikacji REST mam filtr CORS, który wygląda następująco.

@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 { }
}

Moja wiosenna konfiguracja zabezpieczeń wygląda następująco.

@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);
    }
}

Wszystko, co robią programy obsługi, to wypisywanie odpowiedzi JSON, na przykład {success: true}na podstawie tego, czy użytkownik zalogował się, nie uwierzytelnił się lub wylogował. Do RestAuthenticationEntryPointwygląda następująco.

@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");
    }

}

Jakieś pomysły na temat tego, czego mi brakuje lub co robię źle?

Jane Wayne
źródło
Przypuszczam, że musisz mieć przy sobie również uwierzytelnienie, na przykład token lub coś w tym rodzaju. Masz 2 serwery. Czy obejrzałeś ten samouczek? spring.io/guides/tutorials/spring-security-and-angular-js
Gokhan Oner
@GokhanOner Jak przeprowadzić uwierzytelnienie? To prawdopodobnie brakujący element tego problemu. Poza tym tak, przeszedłem przez te samouczki i nie sądziłem, że są one zgodne z moim podejściem. Pierwsze dwie części dotyczyły uwierzytelniania Http-Basic, trzecia część dotyczyła Redis (nie chciałem lub planowałem uzyskać to jako zależność), a następnie ostatni tutorial dotyczył API Gatewaychmury wiosennej, co uważałem za przesadę .
Jane Wayne
Przypuszczam, że możesz to zrobić bez redis, to tylko magazyn pamięci podręcznej klucza i wartości. Musisz przechowywać token uwierzytelniania i CSRF w sklepie, możliwe wewnątrz mapy w locie. Kluczową sprawą jest tutaj klucz uwierzytelniający. spójrz na przykład: github.com/dsyer/spring-security-angular/tree/master/ ... i stronę z „serwerem zasobów”. Zobaczysz kilka dodatkowych ziaren zdefiniowanych, kolejność filtra CORS również jest ważna. I trochę rekwizytu. zmiany również konieczne.
Gokhan Oner
Ok, zrobiłem szybkie badanie. Wszystko, czego potrzebujesz, aby pozbyć się Redis, to stworzyć fasolę springSessionRepositoryFilter, spójrz na github.com/spring-projects/spring-session/blob/1.0.0.RC1/… , a także sesję Bean i w tym ziarnie zamiast RedisOperationsSessionRepository, możesz użyć MapSessionRepository, który jest również w sesji wiosennej. A potem idź za przykładem.
Gokhan Oner

Odpowiedzi:

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

}

Nie ma potrzeby dodatkowego definiowania tego filtru, wystarczy dodać tę klasę. Wiosna zostanie zeskanowana i doda ją za Ciebie. SimpleCORSFilter. Oto przykład: przyciski włączania sprężyny

abosancic
źródło
Kilka pytań. 1) Gdzie mam umieścić stałe łańcuchowe HEADERSi X_REDIRECT_LOCATION_HEADER? 2) Czy wiersz request.getRequestURL());jest literówką lub błędem kopiowania / wklejania? 3) Dlaczego nie sprawdzasz OPTIONSi nie kontynuujesz pracy z łańcuchem filtrów?
Jane Wayne
2
Ale blokuje wykonanie AuthenticationEntryPoint .. Proszę o przewodnik
Pra_A,
1
Dziękuję bardzo, niesamowicie pomogło mi to w mojej walce o to, by wiosna i żar współpracowały ze sobą. Zdrowie przyjacielu!
Tomasz Szymanek
FindBugs nie lubi ustawiać parametru nagłówka z: request.getHeader("Origin")jak pokazano powyżej z powodu podziału odpowiedzi HTTP
Glenn
3
Jeśli w Twojej aplikacji są inne filtry, ten filtr musi mieć najwyższy priorytet, dodając do niego adnotację @Order(Ordered.HIGHEST_PRECEDENCE) .
Shafiul
43

Byłem w podobnej sytuacji. Po przeprowadzeniu badań i testów, oto moje ustalenia:

  1. W przypadku Spring Boot zalecanym sposobem włączenia globalnego CORS jest zadeklarowanie w Spring MVC i połączenie z drobnoziarnistą @CrossOriginkonfiguracją jako:

    @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("*");
                }
            };
        }
    }
    
  2. Teraz, ponieważ używasz Spring Security, musisz włączyć CORS również na poziomie Spring Security, aby umożliwić mu wykorzystanie konfiguracji zdefiniowanej na poziomie Spring MVC jako:

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and()...
        }
    }
    

    Oto bardzo doskonały tutorial wyjaśniający obsługę CORS we frameworku Spring MVC.

Yogen Rai
źródło
3
ups, działa z tą zmianą http .csrf () .disable () .cors () .and ()
marti_
1
@Osgux dobrze to słyszeć :) ponieważ używam JWT do autoryzacji i są one bezpieczne dla csrf, nie umieściłem tego tam .. nie zapomnij o głosowaniu, jeśli to pomogło :)
Yogen Rai
tak, dodałem +1 = D
marti_
@Marcel jaki problem otrzymujesz?
Yogen Rai,
Nie udało się załadować <mój adres spoczynkowy>: Odpowiedź na żądanie inspekcji wstępnej nie przechodzi kontroli dostępu: w żądanym zasobie nie ma nagłówka „Access-Control-Allow-Origin”. Dlatego źródłolocalhost: 8090 ” nie ma dostępu.
Marcel
22

Jeśli chcesz włączyć CORS bez używania filtrów lub bez pliku konfiguracyjnego, po prostu dodaj

@CrossOrigin

na górę kontrolera i działa.

Eduardo Dennis
źródło
4
Jakie są zagrożenia bezpieczeństwa, stosując to podejście?
Balaji Vignesh
U mnie zadziałało, próbowałem dodać nagłówki bezpośrednio do odpowiedzi, ale nie zadziałało, ponieważ inspekcja wstępna nie była obsługiwana. Myślę, że nie jest to zabezpieczone, ale może być używane przez niektóre aplikacje wewnętrzne.
amisiuryk
Pracował dla mnie. całkiem poręczne rozwiązanie do zastosowań wewnętrznych.
Ajay Kumar
8

Aby zbudować na innych odpowiedziach powyżej, w przypadku, gdy masz aplikację usługi Spring boot REST (nie Spring MVC) z zabezpieczeniami Spring, wystarczy WebMvcConfigurerwłączyć CORS za pomocą zabezpieczeń Spring (jeśli używasz Spring MVC, użycie fasoli, jak wspomniał Yogen, może być sposób postępowania, ponieważ zabezpieczenia Spring zostaną przekazane do wspomnianej tam definicji CORS)

Musisz więc mieć konfigurację zabezpieczeń, która wykonuje następujące czynności:

@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;
}

}

Ten link zawiera więcej informacji na ten temat: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors

Uwaga:

  1. Włączenie CORS dla wszystkich źródeł (*) dla aplikacji wdrożonej prod może nie zawsze być dobrym pomysłem.
  2. CSRF można włączyć bez żadnych problemów poprzez dostosowanie Spring HttpSecurity
  3. W przypadku, gdy masz włączone uwierzytelnianie w aplikacji ze Springiem ( UserDetailsServicena przykład za pomocą ), configuration.setAllowCredentials(true);należy dodać

Przetestowano pod kątem Spring boot 2.0.0.RELEASE (tj. Spring 5.0.4.RELEASE i Spring security 5.0.3.RELEASE)

Deepak
źródło
To rozwiązało mój problem. Będąc nowym w Spring i Spring Boot, zdałem sobie sprawę, że nie buduję z Sring MVC. Miałem klienta Vue.js. Inne odpowiedzi wydawały się dotyczyć Spring MVC, ale ta odpowiedź ładnie pasowała do mojego już zaimplementowanego uwierzytelniania i autoryzacji.
jaletechs
Cześć @jaletechs, ja też używam nuxtJs (frameworka vuejs), ale jeśli chodzi o ustawianie plików cookie, to nie działa. czy byłbyś na tyle uprzejmy, aby w tym pomóc.
KAmit
6

Używam spring boot 2.1.0i to, co zadziałało, to

A. Dodaj mapowania korsów według:

@Configuration
public class Config implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*");
    }
}

B. Dodaj poniższą konfigurację do mojej HttpSecuritydla zabezpieczenia wiosennego

.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;
    }
})

Również w przypadku serwera proxy Zuul możesz użyć tego ZAMIAST A i B (po prostu użyj, HttpSecurity.cors()aby włączyć go w zabezpieczeniach Spring):

@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);
}
Wrz GH
źródło
zwróć nowy CorsFilter (źródło); nie taki błąd konstruktora
Aadam
@Aadam Czy używasz tej samej wersji butów sprężynowych co ja?
Wrz GH
2.1.5 jest w użyciu
Aadam
@Aadam To może być niestety powód.
Wrzesień GH
@Aadam Upewnij się, że używasz CorsFilter od org.springframework.web.filter.CorsFilter. Miałem ten sam problem, gdy przypadkowo użyłem go z paczek Catalina.
Wrz GH
5

To działa dla mnie:

@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;
        }
      });

      //...

   }

   //...

}
Renan Polisciuc
źródło
Chociaż ten kod może odpowiedzieć na pytanie, zapewnia dodatkowy kontekst dotyczący tego, dlaczego i / lub jak ten kod odpowiada, poprawia jego długoterminową wartość.
Adriano Martins
1
W przypadku, gdy uwierzytelnianie jest włączone za pośrednictwem zabezpieczeń Spring, to config.setAllowCredentials (true); MUSI zostać wstawione, w przeciwnym razie żądania CORS nadal będą kończyć się niepowodzeniem
Deepak
2

Dla mnie jedyną rzeczą, która zadziałała w 100%, gdy zastosowano zabezpieczenia wiosenne, było pominięcie całego dodatkowego puchu dodatkowych filtrów i fasoli oraz jakiejkolwiek pośredniej „magii”, którą ludzie sugerowali, że działa dla nich, ale nie dla mnie.

Zamiast tego po prostu wymuś napisanie potrzebnych nagłówków za pomocą zwykłego 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"));
    }
}

To najbardziej bezpośredni i wyraźny sposób, w jaki to robię. Mam nadzieję, że to komuś pomoże.

Jeronimo Backes
źródło
1

Krok 1

Dodanie adnotacji do kontrolera z @CrossOriginadnotacją pozwoli na konfiguracje CORS.

@CrossOrigin
@RestController
public class SampleController { 
  .....
}

Krok 2

Spring ma już CorsFilter, mimo że możesz po prostu zarejestrować swój własny CorsFilter jako ziarno, aby zapewnić własną konfigurację w następujący sposób.

@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);
}
Saveendra Ekanayake
źródło
0

Sprawdź ten:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    ...
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
    ...
}
yibourkelidrissi
źródło
Chociaż ten kod może odpowiedzieć na pytanie, zapewnia dodatkowy kontekst dotyczący tego, dlaczego i / lub jak ten kod odpowiada, poprawia jego długoterminową wartość.
rollstuhlfahrer
0

Rozszerzenie klasy WebSecurityConfigurerAdapter i przesłanianie metody configure () w klasie @EnableWebSecurity zadziałałoby: Poniżej znajduje się przykładowa klasa

@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();
        }
    });
   }
}
keyRen
źródło
0

Jeśli pierwotnie twój program nie używa zabezpieczeń Spring i nie stać go na zmianę kodu, utworzenie prostego odwrotnego proxy może załatwić sprawę. W moim przypadku użyłem Nginx z następującą konfiguracją:

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;
    }
  }
}

Mój program słucha : 8080 .

ODNIESIENIE: CORS na Nginx

Orvyl
źródło
0

To właśnie zadziałało dla mnie.

@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);
    }

}
Dennis Crissman II
źródło
0

Ta odpowiedź kopiuje odpowiedź @abosancic, ale zapewnia dodatkowe bezpieczeństwo, aby uniknąć exploita CORS .

Wskazówka 1: Nie odzwierciedlaj przychodzącego źródła bez sprawdzenia listy dozwolonych hostów, do których można uzyskać dostęp.

Wskazówka 2: Zezwalaj na żądania poświadczeń tylko w przypadku hostów z białej listy.

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;
        }
    }
}
Shailesh Pratapwar
źródło
0

W naszej aplikacji Spring Boot skonfigurowaliśmy CorsConfigurationSource w ten sposób.

Sekwencja dodawania, allowedOrignsa następnie ustawiania, applyPermitDefaultValues()pozwala Springowi ustawić domyślne wartości dla dozwolonych nagłówków, ujawnionych nagłówków, dozwolonych metod itp., Więc nie musimy ich określać.

    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);
    }
Poznaj Shaha
źródło
0

Po prostu utwórz jedną klasę , wszystko będzie dobrze z tym:

        @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 {
            }
        }
Imranmadbar
źródło
0

To właśnie zadziałało w moim przypadku, aby wyłączyć CORS między uruchomieniem Spring i 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);
    }
}

Musiałem zmodyfikować konfigurację zabezpieczeń również jak poniżej:

        @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());
        }
Gil Nz
źródło