48 votes

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

Je suis à l'aide d' Auth0 pour mon authentification de l'utilisateur pour autoriser uniquement les utilisateurs enregistrés d'accéder à un Ressort (Boot) RestController. À ce point, je suis de créer en temps réel une fonctionnalité de message, où les utilisateurs peuvent envoyer des messages à partir de l' Angular 2 client (localhost:4200) pour le Printemps serveur (localhost:8081) à l'aide d' stompjs et sockjs.

Lorsque vous essayez de créer un Stomp-client et le démarrage d'une connexion j'ai le message suivant dans la console d'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. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Après des recherches sur ce problème, il semble comme il n'est pas possible de définir l'option origines = * et les informations d'identification = true dans le même temps. Comment puis-je résoudre ce problème quand j'ai déjà le permis origine dans le WebSocketConfig pour le client de domaine?

Angulaire à 2 composants

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 (temporairement permet à tous)

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

Mise à JOUR

Après quelques tests supplémentaires et de la recherche, il semble que le problème se produit uniquement à l'aide de Chrome. Problème peut-être lié à: https://github.com/sockjs/sockjs-node/issues/177

Mise à JOUR

J'ai créé le CORSFilter comme chsdk mentionné et utilisé le addFilterBefore() la méthode: 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é par le débogage, mais le message d'erreur continue à apparaître sur le côté client, même si la bonne Access-Control-Allow-Origin est:

enter image description here

38voto

chsdk Points 64

Problème:

Vous n'êtes pas de la configuration d' 'Access-Control-Allow-Origin' correctement et de votre configuration actuelle est tout simplement ignoré par le serveur.

Situation:

La trace de la pile d'Erreur dit:

La valeur de l' 'Access-Control-Allow-Origin' - tête de la réponse ne doit pas être le joker '*' lors de la demande d'informations d'identification du mode "inclure". Origine 'http://localhost:4200' est donc pas autorisé à accéder.

Cela signifie que, hormis le fait que vous ne pouvez pas définir d' 'Access-Control-Allow-Origin' pour les génériques "*", votre nom de domaine 'http://localhost:4200' n'est pas autorisé à accéder aussi.

Pour répondre à votre question:

Comment puis-je résoudre ce problème quand j'ai déjà le permis origine dans le WebSocketConfig pour le client de domaine?

Solution:

Je suppose que vous n'avez pas besoin de définir le permis origine dans l' WebSocketConfig parce qu'il est destiné à configurer les WebSocket style de messagerie dans les applications web, comme indiqué dans WebSocket Soutien au Printemps de la documentation, vous devez le configurer dans un CORSFilter classe de configuration qu'il est destiné à configurer le Printemps des Filtres de l'application Web access.

C'est ce que 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 pouvez avoir besoin de prendre un coup d'oeil au soutien de la SCRO dans le Cadre du Printemps et de l' Activation de l'Origine de la Croix de Demandes pour un Service Web RESTful pour en savoir plus à ce sujet.

6voto

VikingCode Points 754

Cela n'a rien à voir avec votre printemps ou angulaire code de l'application.

Intro à votre problème
L' Access-Control-Allow-Origin est une partie de CORS (Cross-Origin Resource sharing) mécanisme qui donne des serveurs web de la croix-domaine des contrôles d'accès. Il est en place pour protéger votre application/site de CSRF (Cross-Site Request Forgery).

LA SCRO / CSRF

Le problème
Maintenant, si nous avons lu votre erreur soigneusement

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 Access-Control-Allow-Origin - tête ne peut pas être un caractère générique.

Avec d'autres mots, maintenant votre back-end est à dire tout le monde de tout le web peut exécuter du code sur mon site.

Ce que nous voulons atteindre: Limite de l'origine à seulement avant la fin de l'app (ng2).

Solution Maintenant, parce que vous êtes à l'aide de Printemps, je vais supposer que vous l'utilisez avec Apache Tomcat en tant que votre serveur web.

CORS sont difined comme filtre dans votre site web.conf (tomcat dossier)

trouvez cette ligne

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

et modifier la * à http://localhost:4200

pour plus d'informations sur la config de la SCRO dans Tomcat veuillez lire ce

EDIT ( Printemps de démarrage )
Parce que vous êtes à l'aide de spring boot, vous pouvez déléguer la configuration de la scro du cadre.

Veuillez suivre ce tutoriel sur le printemps.io ( comme chsdk proposé )pour obtenir une meilleure compréhension de la SCRO de configuration de spring boot .

4voto

ma réponse est trop tard mais je vais poster ce que si quelqu'un pouvait faire face au même problème, j'ai été confrontée à la même croix-origine de la question.

Fondamentalement, si vous utilisez le Printemps de Sécurité mis en place sur votre serveur d'application côté, c'est Probablement lui qui bloque websocket handshaker

Vous devez indiquer le Printemps de sécurité pour permettre à votre websocket points de terminaison afin de permettre à douille poignée de main... à l'aide de

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

Donc sockjs sera en mesure maintenant d'envoyer un GET (Http) demande de la poignée de main avant de passer au protocole Websocket

C'est le Printemps, la Configuration de sécurité

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

C'est WebSocket de configuration du 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");
    }
}

-3voto

Wentao Wan Points 38

Ajoutez simplement .setAllowedOrigins("*") à la configuration webSocket.

 @Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    stompEndpointRegistry.addEndpoint("/yourEndpoint");
    stompEndpointRegistry.addEndpoint("/yourEndpoint").setAllowedOrigins("*").withSockJS();
}
 

La version de webSocket est 1.4.1.RELEASE, vous devez mettre à jour votre version si la méthode n'a pas été affichée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X