web-dev-qa-db-fra.com

Spring WebSocket Connexion avec SockJS à un autre domaine

WebSockets au printemps est un sujet assez nouveau que je suis fatigué d'en trouver un peu plus.

Mon problème est de me connecter à un service d'un domaine différent, je travaille avec Lineman pour construire le côté frontal et Spring Boot lorsque je fais le côté principal, avec cela j'ai ces applications sur deux ports différents: 8000 et 8080 sur localhost.

J'ai eu des problèmes avec l'en-tête "Access-Control-Allow-Origin" mais je l'ai résolu en ajoutant un filtre côté serveur qui a ajouté l'origine autorisée à l'en-tête. Après cela, j'ai commencé à obtenir l'erreur suivante lors de la connexion:

GET http://localhost:8080/socket/info 403 (Forbidden)
AbstractXHRObject._start @ sockjs-0.3.4.js:807
(anonymous function) @sockjs-0.3.4.js:841

Je n'ai pas Spring Security dans le projet donc ce n'est pas un problème d'autorisation, l'erreur pointe vers sockJS: that.xhr.send (payload); - où la charge utile n'est jamais définie. J'ai essayé mais je n'ai pas pu trouver la racine de l'appel où il peut avoir commencé.

Je pensais si je devais ajouter des informations supplémentaires à SockJS et Stomp lors de la configuration de la connexion, mais il n'y a pas beaucoup d'exemples et de notes dans les deux pages wiki de ces outils.

Ci-dessous, vous trouverez le code de connexion JS.

var socket = new SockJS("http://localhost:8080/socket");
client = Stomp.over(socket);

client.connect({'login': BoatsGame.userName,
                    'passcode': 'guest'},
            function (frame) {
....

The Server Side has a MessageBroker configured :    


@Configuration
@EnableWebSocketMessageBroker
public class MessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
     ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
     container.setMaxTextMessageBufferSize(8192);
     container.setMaxBinaryMessageBufferSize(8192);
     return container;
}

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
     //config.enableStompBrokerRelay("/queue", "/topic");
     config.enableSimpleBroker("/queue", "/topic","/user");
     config.setApplicationDestinationPrefixes("/BoatBattleGame");
}

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

J'ai également essayé de configurer un MessageHandler car il a la possibilité de définir OriginAllowe lors de la configuration, mais je ne sais pas comment il est connecté au courtier.

Enfin, cette configuration fonctionne correctement lors de l'exécution sur un port.

23
Sniady

La réponse de Jax était correcte :)

La méthode registerStompEndpoints nous donne la possibilité de définir les origines autorisées. Nous devons l'ajouter avant l'option "withSockJs ()".

    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/BO/socket").setAllowedOrigins("*").withSockJS();
    }
59
Sniady

À tous ceux qui accèdent à ce ticket en raison de la réponse interdite 403 lorsqu'ils essaient de se connecter via un SockJsClient à un autre domaine:

Le problème se pose lorsque vous essayez de faire un GET à l'url/info, dans le cadre de la négociation. La réponse renvoie en fait un 200 via WGET ainsi que via un navigateur. Ce n'est que via SockJsClient que cela ne fonctionne pas.

Après avoir essayé différentes solutions, la seule qui a vraiment résolu le problème est d'écrire une classe qui implémente Transport et InfoReceiver. De cette façon, le développeur peut gérer directement cette partie de la prise de contact. Fondamentalement, vous effectuez le travail dans la méthode executeInfoRequest ():

@Override
public String executeInfoRequest(URI infoUrl, HttpHeaders headers) {
    HttpGet getRequest = new HttpGet(infoUrl); // eventually add headers here
    HttpClient client = HttpClients.createDefault();

    try {
        HttpResponse response = client.execute(getRequest);
        List<String> responseOutput = IOUtils.readLines(response.getEntity().getContent());

        return responseOutput.get(0);
    } catch (IOException ioe) {
        ...
    }
}

J'ai défini TransportType.XHR comme type de transport.

6
Mauro

Dans mon cas, j'ai dû ajouter ces configurations pour que SockJS/STOMP fonctionne avec CORS:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer
{
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(false)
                .maxAge(3600)
                .allowedHeaders("Accept", "Content-Type", "Origin", 
"Authorization", "X-Auth-Token")
                .exposedHeaders("X-Auth-Token", "Authorization")
                .allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
    }
}
3
Frithjof Schaefer

j'ai trouvé cette solution en créant un filtre

package com.diool.notif.config;

import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import Java.io.IOException;

@Component
public class SimpleCORSFilter implements Filter {

    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SimpleCORSFilter.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("Initilisation du Middleware");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest requestToUse = (HttpServletRequest)servletRequest;
        HttpServletResponse responseToUse = (HttpServletResponse)servletResponse;

        responseToUse.setHeader("Access-Control-Allow-Origin",requestToUse.getHeader("Origin"));
        filterChain.doFilter(requestToUse,responseToUse);
    }

    @Override
    public void destroy() {

    }
}
1
Fabricelepro