CORS avec spring-boot et angularjs ne fonctionne pas


87

J'essaie d'appeler les points de terminaison REST sur une application (application à démarrage à ressort) à partir d'une autre (angularjs). Les applications s'exécutent sur les hôtes et ports suivants.

  • Application REST, utilisant le démarrage à ressort http://localhost:8080
  • Application HTML, utilisant angularjs, http://localhost:50029

J'utilise également spring-securityavec l'application spring-boot. À partir de l'application HTML, je peux m'authentifier auprès de l'application REST, mais par la suite, je ne peux toujours pas accéder à un point de terminaison REST. Par exemple, j'ai un service angularjs défini comme suit.

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

Le contrôleur angularjs ressemble à ce qui suit.

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

Lors de l'appel à http://localhost:8080/api/admin/isloggedin, je reçois un 401 Unauthorized.

Du côté de l'application REST, j'ai un filtre CORS qui ressemble à ce qui suit.

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

Ma configuration de sécurité Spring ressemble à ce qui suit.

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

Tout ce que font les gestionnaires est d'écrire une réponse JSON comme {success: true}si l'utilisateur s'est connecté, n'a pas réussi à s'authentifier ou s'est déconnecté. Le RestAuthenticationEntryPointressemble à ce qui suit.

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

}

Des idées sur ce qui me manque ou ce que je fais mal?


Je suppose que vous devez également porter l'authentification, comme un jeton ou quelque chose du genre. Vous avez 2 serveurs. Avez-vous regardé ce tutoriel? spring.io/guides/tutorials/spring-security-and-angular-js
Gokhan Oner

@GokhanOner Comment puis-je effectuer l'authentification? C'est probablement la pièce manquante à ce problème. De plus, oui, j'ai suivi ces tutoriels et je ne pensais pas qu'ils correspondaient à mon approche. Les deux premières parties concernaient l'authentification Http-Basic, puis la troisième partie traitait de Redis (je ne voulais pas ou ne prévoyais pas de l'obtenir en tant que dépendance), puis le dernier didacticiel portait sur le API Gatewaycloud avec spring, que je pensais exagéré. .
Jane Wayne

Je suppose que vous pouvez le faire sans le redis, c'est juste un magasin de cache clé-valeur. Vous devez stocker l'authentification et le jeton CSRF sur un magasin, possible à l'intérieur de la carte à la volée. L'élément clé ici est la clé d'authentification. regardez l'exemple: github.com/dsyer/spring-security-angular/tree/master / ... et la page avec "serveur de ressources". Vous verrez quelques beans supplémentaires définis, l'ordre du filtre CORS également important. Et un accessoire. des changements sont également nécessaires.
Gokhan Oner

Ok, j'ai fait une recherche rapide. Tout ce dont vous avez besoin, pour vous débarrasser de Redis, est de créer un bean springSessionRepositoryFilter, regardez github.com/spring-projects/spring-session/blob/1.0.0.RC1/… , et aussi sessionRepository bean et dans ce bean, au lieu de RedisOperationsSessionRepository, vous pouvez utiliser MapSessionRepository, qui est également en session de printemps. Et puis suivez l'exemple.
Gokhan Oner

Réponses:


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

}

Plus besoin de définir ce filtre, ajoutez simplement cette classe. Spring sera numérisé et l'ajoutera pour vous. SimpleCORSFilter. Voici l'exemple: spring-enable-cors


Quelques questions. 1) Où suis-je censé mettre les constantes de chaîne HEADERSet X_REDIRECT_LOCATION_HEADER? 2) La ligne est-elle request.getRequestURL());une faute de frappe ou une erreur de copier / coller? 3) Pourquoi ne pas vérifier OPTIONSet continuer simplement avec la chaîne de filtrage?
Jane Wayne

2
Mais il bloque pour exécuter AuthenticationEntryPoint .. Veuillez guider
Pra_A

1
Merci beaucoup, cela m'a énormément aidé dans ma lutte pour que le printemps et la braise travaillent ensemble. Salut mon pote!
Tomasz Szymanek

FindBugs n'aime pas définir un paramètre d'en-tête avec: request.getHeader("Origin")comme indiqué ci-dessus en raison du fractionnement de la réponse HTTP
Glenn

3
S'il existe d'autres filtres dans votre application, ce filtre doit avoir la priorité la plus élevée en annotant le filtre avec @Order(Ordered.HIGHEST_PRECEDENCE) .
Shafiul

43

J'avais été dans la même situation. Après avoir fait des recherches et des tests, voici mes résultats:

  1. Avec Spring Boot, la méthode recommandée pour activer CORS global est de déclarer dans Spring MVC et de la combiner avec une @CrossOriginconfiguration fine comme:

    @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. Désormais, puisque vous utilisez Spring Security, vous devez également activer CORS au niveau de Spring Security pour lui permettre d'exploiter la configuration définie au niveau Spring MVC comme:

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

    Voici un très excellent tutoriel expliquant la prise en charge de CORS dans le framework Spring MVC.


3
ups cela fonctionne avec ce changement http .csrf () .disable () .cors () .and ()
marti_

1
@Osgux c'est bien d'entendre ça :) puisque j'utilise JWT pour l'autorisation et qu'ils sont sûrs csrf, je ne l'ai pas mis là .. n'oubliez pas de voter si cela a aidé :)
Yogen Rai

yep j'ai ajouté +1 = D
marti_

@Marcel quel problème avez-vous?
Yogen Rai

Échec du chargement de <mon adresse de repos>: la réponse à la demande de contrôle en amont ne passe pas la vérification de contrôle d'accès: aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L' accès d' origine ' localhost: 8090 ' n'est donc pas autorisé.
Marcel

22

Si vous souhaitez activer CORS sans utiliser de filtres ou sans fichier de configuration, ajoutez simplement

@CrossOrigin

vers le haut de votre contrôleur et cela fonctionne.


4
Quels sont les risques de sécurité en suivant cette approche?
Balaji Vignesh

Cela a fonctionné pour moi, j'ai essayé d'ajouter des en-têtes directement à la réponse, mais cela n'a pas fonctionné car le contrôle en amont n'était pas géré. Je pense que ce n'est pas sécurisé mais que certaines applications internes pourraient être utilisées.
amisiuryk

A travaillé pour moi. solution assez pratique pour application interne.
Ajay Kumar le

8

Pour s'appuyer sur les autres réponses ci-dessus, au cas où vous auriez une application de service Spring Boot REST (pas Spring MVC) avec la sécurité Spring, l'activation de CORS via la sécurité Spring suffit (si vous utilisez Spring MVC, utilisez un WebMvcConfigurer bean comme mentionné par Yogen pourrait être la voie à suivre car la sécurité de Spring déléguera à la définition CORS mentionnée ici)

Vous devez donc disposer d'une configuration de sécurité qui effectue les opérations suivantes:

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

}

Ce lien contient plus d'informations sur le même: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors

Remarque:

  1. L'activation de CORS pour toutes les origines (*) pour une application déployée prod n'est pas toujours une bonne idée.
  2. CSRF peut être activé via la personnalisation Spring HttpSecurity sans aucun problème
  3. Si vous avez activé l'authentification dans l'application avec Spring (via un UserDetailsServicepar exemple), le configuration.setAllowCredentials(true);doit être ajouté

Testé pour Spring boot 2.0.0.RELEASE (c'est-à-dire Spring 5.0.4.RELEASE et Spring security 5.0.3.RELEASE)


Cela a résolu mon problème. Étant nouveau dans Spring et Spring Boot, j'ai réalisé que je ne construisais pas avec Sring MVC. J'avais un client Vue.js. D'autres réponses semblaient être pour Spring MVC, mais cette réponse s'intégrait bien avec mon authentification et autorisation déjà implémentées.
jaletechs

Salut @jaletechs, j'utilise aussi nuxtJs (un framework vuejs) mais quand il s'agit de définir un cookie, cela ne fonctionne pas. seriez-vous assez aimable pour aider à ce sujet.
KAmit le

6

J'utilise spring boot 2.1.0et ce qui a fonctionné pour moi était de

A. Ajoutez des mappages de cors en:

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

B.Ajoutez la configuration ci-dessous à my HttpSecuritypour la sécurité du printemps

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

Également dans le cas d'un proxy Zuul, vous pouvez utiliser ceci AU LIEU DE A et B (utilisez simplement HttpSecurity.cors()pour l'activer dans la sécurité 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);
}

retourne un nouveau CorsFilter (source); pas une telle erreur de constructeur
Aadam

@Aadam Utilisez-vous la même version de Spring Boot que moi?
Sep GH

2.1.5 est en cours d'utilisation
Aadam

@Aadam C'est peut-être la raison malheureusement.
Sep GH

@Aadam Veuillez vous assurer que vous utilisez CorsFilter à partir de org.springframework.web.filter.CorsFilter. J'ai eu le même problème pendant que je l'utilisais accidentellement à partir de paquets catalina.
Sep GH

5

Cela fonctionne pour moi:

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

      //...

   }

   //...

}

Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
Adriano Martins

1
Si l'authentification est activée via la sécurité Spring, alors config.setAllowCredentials (true); DOIT être mis, sinon les requêtes CORS échoueront toujours
Deepak

2

Pour moi, la seule chose qui a fonctionné à 100% lorsque la sécurité du ressort est utilisée était de sauter toutes les peluches supplémentaires de filtres et de haricots supplémentaires et tout ce que les gens «magiques» indirects ont continué à suggérer que cela fonctionnait pour eux mais pas pour moi.

Au lieu de cela, forcez-le simplement à écrire les en-têtes dont vous avez besoin avec un simple 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"));
    }
}

C'est la manière la plus directe et la plus explicite que j'ai trouvée pour le faire. J'espère que ça aide quelqu'un.


1

Étape 1

En annotant le contrôleur avec une @CrossOriginannotation, vous autoriserez les configurations CORS.

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

Étape 2

Spring a déjà un CorsFilter même si vous pouvez simplement enregistrer votre propre CorsFilter en tant que bean pour fournir votre propre configuration comme suit.

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

0

vérifier celui-ci:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    ...
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
    ...
}

Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
rollstuhlfahrer

0

L'extension de la classe WebSecurityConfigurerAdapter et la substitution de la méthode configure () dans votre classe @EnableWebSecurity fonctionneraient: Voici un exemple de classe

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

0

Si à l'origine votre programme n'utilise pas la sécurité Spring et ne peut pas se permettre un changement de code, la création d'un simple proxy inverse peut faire l'affaire. Dans mon cas, j'ai utilisé Nginx avec la configuration suivante:

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

Mon programme écoute : 8080 .

REF: CORS sur Nginx


0

C'est ce qui a fonctionné pour moi.

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

}

0

Cette réponse copie la réponse @abosancic mais ajoute une sécurité supplémentaire pour éviter l'exploit CORS .

Astuce 1: ne reflétez pas l'origine entrante telle quelle sans vérifier la liste des hôtes autorisés à accéder.

Astuce 2: n'autorisez les demandes d'informations d'identification que pour les hôtes en liste blanche.

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

0

Dans notre application Spring Boot, nous avons configuré CorsConfigurationSource comme ceci.

La séquence d'ajout d' allowedOrignsabord, puis de réglage applyPermitDefaultValues()permet à Spring de configurer les valeurs par défaut pour les en-têtes autorisés, les en-têtes exposés, les méthodes autorisées, etc. afin que nous n'ayons pas à les spécifier.

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

0

Faites simplement une seule classe comme, tout ira bien avec ceci:

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

0

C'est ce qui a fonctionné pour moi afin de désactiver CORS entre Spring boot et 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);
    }
}

J'ai dû modifier la configuration de sécurité également comme ci-dessous:

        @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());
        }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.