web-dev-qa-db-fra.com

L'en-tête de la réponse ne doit pas être le caractère générique '*' lorsque le mode d'identification de la demande est 'include'

J'utilise Auth0 pour que mon authentification d’utilisateur autorise uniquement les utilisateurs connectés à accéder à un Spring (Boot) RestController. À ce stade, je crée une fonctionnalité de message en temps réel grâce à laquelle les utilisateurs peuvent envoyer des messages à partir du Angular 2 client (localhost:4200) sur le serveur Spring (localhost: 8081) à l’aide de stompjs et sockjs.

Lorsque j'essaie de créer un client Stomp et de démarrer une connexion, l'erreur de console suivante apparaît:

 The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Après avoir étudié ce problème, il semble impossible de définir les options origins = * et credentials = true en même temps. Comment puis-je résoudre ce problème alors que j'ai déjà défini l'origine autorisée dans WebSocketConfig sur le domaine client?

2 composants angulaires

connect() {
    var socket = new SockJS('http://localhost:8081/chat');
    this.stompClient = Stomp.over(socket);  
    this.stompClient.connect({}, function(result) {
        console.log('Connected: ' + result);
        this.stompClient.subscribe('/topic/messages', function(message) {
            console.log(message);
        });
    });
}    

WebSocketConfig

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200").withSockJS();
    }
}

localhost: 8081/chat/info? t = 1490866768565

{"entropy":-1720701276,"origins":["*:*"],"cookie_needed":true,"websocket":true}

MessageController

public class MessageController {
    @MessageMapping("/chat")
    @SendTo("/topic/messages")
    public Message send(Message message) throws Exception {
        return new Message(message.getFrom(), message.getText());
    }
}

SecurityConfig (autorise temporairement tout)

public class SecurityConfig extends Auth0SecurityConfig {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll();
    }
}

[~ # ~] met à jour [~ # ~]

Après quelques tests et recherches supplémentaires, il semble que le problème ne se produise que sous Chrome. Le problème est peut-être lié à: https://github.com/sockjs/sockjs-node/issues/177

[~ # ~] met à jour [~ # ~]

J'ai créé le CORSFilter comme indiqué par chsdk et utilisé la méthode addFilterBefore (): https://stackoverflow.com/a/40300363/4836952 .

@Bean
CORSFilter corsFilter() {
    CORSFilter filter = new CORSFilter();
    return filter;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(corsFilter(), SessionManagementFilter.class).authorizeRequests().anyRequest().permitAll();
    http.csrf().disable();
}

Je peux voir que le filtre est appelé en le déboguant, mais le message d'erreur continue de s'afficher sur le côté client, même si le contrôle d'accès correct est attribué:

enter image description here

29
Sam

Problème:

Vous ne configurez pas 'Access-Control-Allow-Origin' correctement et votre configuration actuelle est simplement ignorée par le serveur.

Situation:

La trace de la pile d'erreur indique:

La valeur de la 'Access-Control-Allow-Origin' L'en-tête de la réponse ne doit pas être le caractère générique '*' lorsque le mode d'informations d'identification de la demande est 'include'. Origin ' http: // localhost: 42 ' n'est donc pas autorisé à accéder.

Cela signifie que mis à part le fait que vous ne pouvez pas définir 'Access-Control-Allow-Origin' au caractère générique "*", ton domaine 'http://localhost:4200' n'est pas autorisé l'accès aussi.

Pour répondre à ta question:

Comment puis-je résoudre ce problème alors que j'ai déjà défini l'origine autorisée dans WebSocketConfig sur le domaine client?

Solution:

Je suppose que vous n’avez pas besoin de définir l’origine permise dans le WebSocketConfig car il est conçu pour configurer la messagerie de style WebSocket dans les applications Web comme indiqué dans Support WebSocket dans la documentation Spring , vous devrez le configurer dans une classe de configuration CORSFilter afin de configurer les filtres Spring pour Web. accès aux applications.

C'est ce dont vous aurez besoin dans votre CORSFilter.Java classe de configuration:

public class CORSFilter implements Filter {

    // This is to be replaced with a list of domains allowed to access the server
  //You can include more than one Origin here
    private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200"); 

    public void destroy() {

    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;

            // Access-Control-Allow-Origin
            String Origin = request.getHeader("Origin");
            response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(Origin) ? Origin : "");
            response.setHeader("Vary", "Origin");

            // Access-Control-Max-Age
            response.setHeader("Access-Control-Max-Age", "3600");

            // Access-Control-Allow-Credentials
            response.setHeader("Access-Control-Allow-Credentials", "true");

            // Access-Control-Allow-Methods
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

            // Access-Control-Allow-Headers
            response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN");
        }

        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }
}

Vous pouvez voir l'utilisation de:

private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200");

Pour définir la liste des domaines autorisés à accéder au serveur.

Références:

Vous devrez peut-être jeter un œil à prise en charge de CORS dans Spring Framework et Activation des demandes d’origine croisée pour un service Web RESTful pour en savoir plus à ce sujet.

16
cнŝdk

Cela n’a rien à voir avec votre ressort ou angular app.

Introduction à votre problème
Le accès-contrôle-autoriser-origine fait partie de CORS (partage de ressources d'origine croisée) mécanisme qui donne aux serveurs Web des contrôles d'accès entre domaines. Il est en place pour protéger votre application/site de CSRF (falsification de requêtes intersites).

CORS / CSRF

Le problème
Maintenant, si nous lisons attentivement votre erreur

The value of the 'Access-Control-Allow-Origin' header in the response must 
not be the wildcard '*' when the request's credentials mode is 'include'. 
Origin 'http://localhost:4200' is therefore not allowed access.

Il est dit que l'en-tête Access-Control-Allow-Origin ne peut pas être un caractère générique.

En d'autres termes, maintenant, votre back-end dit à tout le monde que tout le monde peut exécuter du code sur mon site.

Ce que nous voulons réaliser : Limitez l’origine à votre application front-end (ng2).

Solution Maintenant, parce que vous utilisez Spring, je suppose que vous l'utilisez avec Apache Tomcat comme serveur Web principal.

Les CORS sont définis comme filtre dans votre web.conf (dossier Tomcat)

trouver cette ligne

<init-param>
  <param-name>cors.allowed.origins</param-name>
  <param-value>*</param-value>
</init-param>

et remplacez le * par http: // localhost: 42

pour plus d'informations sur la configuration de CORS dans Tomcat veuillez lire ceci

[~ # ~] éditer [~ # ~] (démarrage du printemps)
Comme vous utilisez un démarrage à ressort, vous pouvez déléguer la configuration des cors au framework.

Veuillez suivre ce tutoriel sur spring.io (comme chsdk proposé) pour mieux comprendre la configuration de CORS avec une botte à ressort.

6
VikingCode

ma réponse est trop tard, mais je publie ceci si quelqu'un pouvait faire face au même problème, j'ai été confronté au même problème d'origine croisée.

En gros, si vous utilisez Spring Security implémenté sur votre application côté serveur, c'est probablement lui qui bloque Websocket Handshaker

Vous devez indiquer à Spring Security d'autoriser les points de terminaison de votre websocket afin de permettre la prise de connexion du socket ...

.antMatchers("/socket/**").permitAll()

Donc, sockjs sera maintenant en mesure d’envoyer une demande GET (Http) pour un échange de mains avant de passer au protocole Websocket

Ceci est la configuration de sécurité Spring

package org.souhaib.caremy.security.module.config;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint).and()
            .authorizeRequests()
            .antMatchers(SecurityParams.PUBLIC_ROUTES).permitAll()
            .antMatchers("/socket/**").permitAll();

    http.csrf().disable();
}}

Ceci est la configuration de WebSocket Broker

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/socket")
                .setAllowedOrigins("http://localhost:4200")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app")
                .enableSimpleBroker("/chat");
    }
}
2
BenFarhat Souhaib