L'en-tête de la réponse ne doit pas être le Joker '*' lorsque le mode d'authentification de la requête est 'include'

j'utilise Auth0 pour mon authentification d'utilisateur pour permettre seulement aux utilisateurs connectés d'accéder à un ressort (Boot) RestController. À ce stade, je crée une fonctionnalité de message en temps réel où les utilisateurs peuvent envoyer des messages à partir du Angular 2 client (localhost:4200) au serveur de printemps (localhost: 8081) en utilisant stompjs et sockjs.

lors de la création D'un client Stomp et du démarrage d'une connexion, je reçois l'erreur suivante de la console:

 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 problème il semble qu'il ne soit pas possible de définir l'option origins = * et credentials = true en même temps. Comment puis-je résoudre cela alors que j'ai déjà défini l'origine autorisée dans le WebSocketConfig au Domaine client?

composante angulaire 2

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 (permis temporaires tous)

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

UPDATE

après d'autres tests et recherches, il semble que le problème ne se pose qu'avec Chrome. Problème peut-être lié à: https://github.com/sockjs/sockjs-node/issues/177

UPDATE

j'ai créé le CORSFilter comme chsdk mentionné 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 à apparaître sur le côté client même si le bon Access-Control-Allow-Origin est défini:

enter image description here

23
demandé sur Community 2017-03-30 13:09:21

4 réponses

Problème:

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

Situation:

La trace de la pile d'Erreur dit:

La valeur 'Access-Control-Allow-Origin' en-tête de la réponse ne doit pas être le joker '*' lorsque le mode d'authentification de la requête est'include'. Origine 'http://localhost:4200 ' n'est donc pas admis accès.

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

pour répondre À ta question:

comment résoudre ce problème alors que j'ai déjà défini l'origine autorisée dans le WebSocketConfig au Domaine client?

Solution:

je suppose que vous n'avez pas besoin de définir le permis origine dans le WebSocketConfig parce que c'est fait pour configurer WebSocket style de messagerie dans les applications web comme indiqué dans le WebSocket Support au Printemps de documentation, vous devez le configurer dans un CORSFilter classe de configuration comme il est destiné à configurer les filtres de ressort pour l'accès à l'application Web.

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

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

Références:

Vous pouvez avoir besoin de prendre un coup d'oeil à soutien de la SCRO dans le Framework Spring et activating Cross Origin Requests for a RESTful Web Service pour en savoir plus.

14
répondu chŝdk 2017-04-14 11:06:08

cela n'a rien à voir avec votre ressort ou votre code d'application angulaire.

Intro à votre problème

Access-Control-Allow-Origin fait partie de CORS (Cross-Origin Resource Sharing) mécanisme qui donne aux serveurs web des contrôles d'accès inter-domaines. Il est en place pour protéger votre application/site de CSRF (Cross-Site Request Forgery).

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

avec d'autres mots, maintenant votre back-end est de dire que tout le monde d'allover 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, puisque vous utilisez Spring, je suppose que vous l'utilisez avec Apache Tomcat comme serveur web d'arrière-plan.

les CORS sont définis comme des filtres dans votre web.conf (tomcat dossier)

trouver cette ligne

<init-param>
  <param-name>cors.allowed.origins</param-name>
  <param-value>*</param-value>
</init-param>
http://localhost:4200

pour plus d'informations sur la configuration de CORS dans Tomcat merci de lire ce

EDIT (Botte de printemps)

Comme vous utilisez le démarrage à ressort, vous pouvez déléguer la configuration de cors au framework.

Veuillez suivre ce tutoriel sur le printemps.io (comme chsdk proposé )pour obtenir une meilleure compréhension de la configuration de CORS avec la botte de ressort .

3
répondu VikingCode 2017-04-14 11:07:58

ma réponse est trop tard mais je poste ceci si quelqu'un pouvait faire face au même problème, j'ai été confronté à la même question 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 dire à la sécurité de Spring d'autoriser vos paramètres websocket afin de permettre la prise en main de la prise... en utilisant

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

Donc sockjs va il est maintenant possible d'envoyer une requête GET (Http) pour le handshaking avant de passer au protocole Websocket

C'est la Configuration de sécurité du ressort

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

ici WebSocket Broker configuration

@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");
    }
}
1
répondu BenFarhat Souhaib 2018-02-18 19:07:04

il suffit d'ajouter .setAllowedOrigins("*") à webSocket config.

@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    stompEndpointRegistry.addEndpoint("/yourEndpoint");
    stompEndpointRegistry.addEndpoint("/yourEndpoint").setAllowedOrigins("*").withSockJS();
}
-1
répondu Wentao Wan 2017-07-03 11:11:35