복붙노트

[SPRING] Spring websocket이 특정 사용자에게 전송

SPRING

Spring websocket이 특정 사용자에게 전송

내 봄 - 웹 응용 프로그램에 대한 사용자 지정 토큰 기반 인증을 추가하고 아래와 같이 스프링 websocket에 대해 동일한 확장

public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket").setAllowedOrigins("*").withSockJS();
    }

    @Override
      public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.setInterceptors(new ChannelInterceptorAdapter() {

            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {

                StompHeaderAccessor accessor =
                    MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    String jwtToken = accessor.getFirstNativeHeader("Auth-Token");
                        if (!StringUtils.isEmpty(jwtToken)) {
                            Authentication auth = tokenService.retrieveUserAuthToken(jwtToken);
                            SecurityContextHolder.getContext().setAuthentication(auth);
                            accessor.setUser(auth);
                            //for Auth-Token '12345token' the user name is 'user1' as auth.getName() returns 'user1'
                        }
                }

                return message;
            }
        });
      }
}

소켓에 연결하는 클라이언트 측 코드는 다음과 같습니다.

var socket = new SockJS('http://localhost:8080/gs-guide-websocket');
    stompClient = Stomp.over(socket);
    stompClient.connect({'Auth-Token': '12345token'}, function (frame) {
        stompClient.subscribe('/user/queue/greetings', function (greeting) {
            alert(greeting.body);
        });
    });

그리고 내 컨트롤러에서 메시지를 보내고 있습니다.

messagingTemplate.convertAndSendToUser("user1", "/queue/greetings", "Hi User1");

인증 토큰 12345token의 경우 사용자 이름은 user1입니다. 그러나 user1에게 메시지를 보내면 클라이언트 쪽에서 수신되지 않습니다. 이것으로 내가 빠진 것이 있습니까?

해결법

  1. ==============================

    1.Websocket 컨트롤러에서 다음과 같이해야합니다 :

    Websocket 컨트롤러에서 다음과 같이해야합니다 :

    @Controller
    public class GreetingController {
    
        @Autowired
        private SimpMessagingTemplate messagingTemplate;
    
        @MessageMapping("/hello")
        public void greeting(Principal principal, HelloMessage message) throws  Exception {
            Greeting greeting = new Greeting();
            greeting.setContent("Hello!");
            messagingTemplate.convertAndSendToUser(message.getToUser(), "/queue/reply", greeting);
        }
    }
    

    클라이언트 측에서는 사용자가 topic / user / queue / reply에 가입해야합니다.

    또한 일부 착신 접두사를 추가해야합니다.

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    
        @Override
        public void configureMessageBroker(MessageBrokerRegistry config) {
            config.enableSimpleBroker("/topic", "/queue" ,"/user");
            config.setApplicationDestinationPrefixes("/app");
            config.setUserDestinationPrefix("/user");
        }
    /*...*/
    }
    

    서버가 / app / hello 대기열에서 메시지를 받으면 사용자의 dto에 메시지를 보내야합니다. 사용자는 사용자의 주체와 같아야합니다.

    귀하의 코드에서 유일한 문제는 귀하의 "/ 사용자"가 목적지 접두사에 없다는 것입니다. 인사 메시지는 / user로 시작하는 대기열에서 메시지를 보냈으므로 차단되었습니다.이 접두사는 등록되지 않았습니다.

    git repo에서 소스를 확인할 수 있습니다. https://github.com/simvetanylen/test-spring-websocket

    희망 그것이 작동합니다!

  2. ==============================

    2.이전 프로젝트에서는 특정 사용자에게 메시지를 보냈습니다. 나는 다음과 같이 썼다.

    이전 프로젝트에서는 특정 사용자에게 메시지를 보냈습니다. 나는 다음과 같이 썼다.

    고객 입장에서:

    function stompConnect(notificationTmpl) 
    {
        var socket = new SockJS('/comm-svr');
        stompClient = Stomp.over(socket);
        var theUserId 
        stompClient.connect({userId:theUserId}, function (frame) {
                debug('Connected: ' + frame);
                stompClient.subscribe('/topic/connect/'+theUserId, function (data)                   {
    //Handle data
                  } 
            });
    }
    

    서버 측

    스프링 websocket 리스너 :

    @Component
    public class WebSocketSessionListener
    {
        private static final Logger logger = LoggerFactory.getLogger(WebSocketSessionListener.class.getName());
        private List<String> connectedClientId = new ArrayList<String>();
    
        @EventListener
        public void connectionEstablished(SessionConnectedEvent sce)
        {
            MessageHeaders msgHeaders = sce.getMessage().getHeaders();
            Principal princ = (Principal) msgHeaders.get("simpUser");
            StompHeaderAccessor sha = StompHeaderAccessor.wrap(sce.getMessage());
            List<String> nativeHeaders = sha.getNativeHeader("userId");
            if( nativeHeaders != null )
            {
                String userId = nativeHeaders.get(0);
                connectedClientId.add(userId);
                if( logger.isDebugEnabled() )
                {
                    logger.debug("Connessione websocket stabilita. ID Utente "+userId);
                }
            }
            else
            {
                String userId = princ.getName();
                connectedClientId.add(userId);
                if( logger.isDebugEnabled() )
                {
                    logger.debug("Connessione websocket stabilita. ID Utente "+userId);
                }
            }
        }
    
        @EventListener
        public void webSockectDisconnect(SessionDisconnectEvent sde)
        {
            MessageHeaders msgHeaders = sde.getMessage().getHeaders();
            Principal princ = (Principal) msgHeaders.get("simpUser");
            StompHeaderAccessor sha = StompHeaderAccessor.wrap(sde.getMessage());
            List<String> nativeHeaders = sha.getNativeHeader("userId");
            if( nativeHeaders != null )
            {
                String userId = nativeHeaders.get(0);
                connectedClientId.remove(userId);
                if( logger.isDebugEnabled() )
                {
                    logger.debug("Connessione websocket stabilita. ID Utente "+userId);
                }
            }
            else
            {
                String userId = princ.getName();
                connectedClientId.remove(userId);
                if( logger.isDebugEnabled() )
                {
                    logger.debug("Connessione websocket stabilita. ID Utente "+userId);
                }
            }
        }
    
        public List<String> getConnectedClientId()
        {
            return connectedClientId;
        }
        public void setConnectedClientId(List<String> connectedClientId)
        {
            this.connectedClientId = connectedClientId;
        }
    }
    

    봄 websocket 메시지 발신자 :

    @Autowired
        private SimpMessagingTemplate msgTmp;
        private void propagateDvcMsg( WebDeviceStatusInfo device )
        {
            String msg = "";
            String userId =((Principal)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getName()
            msgTmp.convertAndSend("/topic/connect"+userId, msg);
        }
    

    유용하게 사용되기를 바랍니다.

  3. from https://stackoverflow.com/questions/43198292/spring-websocket-send-to-specific-people by cc-by-sa and MIT license