相关文章推荐
绅士的匕首  ·  CosyVoice高並發情境 - ...·  4 月前    · 
霸气的麦片  ·  20. WebSocket Support·  3 月前    · 
魁梧的黑框眼镜  ·  33. WebSockets Support·  3 月前    · 
曾经爱过的皮蛋  ·  SpringBoot ...·  3 月前    · 
老实的玉米  ·  Java ...·  1 年前    · 

EnableWebSocketMessageBroker Vs EnableWebSocketSecurity

koonlx · 2024년 9월 24일

stay_connect

목록 보기
9 / 10
  implementation 'org.springframework.boot:spring-boot-starter-websocket'
  implementation 'org.springframework.security:spring-security-messaging'

Spring Boot에서 Socket통신을 구현할 때 위 두 종속성을 자주 사용하는거 같아서 각 종속성의 역할을 알아보고자 한다.
Messaging Stomp Websocket 을 참고하면 이해가 더 잘 될 것이다.

1. @EnableWebSocketMessageBroker

이 예약어는 implementation 'org.springframework.boot:spring-boot-starter-websocket' 종속성을 사용한 Socket 연결을 설정할 때 사용하는 주석이다.
@EnableWebSocketMessageBroker 는 WebSocket 메시징 아키텍처에서 중요한 역할을 하는 설정이다. 이 설정은 메시지 브로커(Message Broker) 를 통해 실시간으로 메시지를 주고받을 수 있는 환경을 구축하는 데 사용된다. 만약 STOMP를 사용하지 않고 싶다면 @EnableWebSocket 를 사용하면 된다.

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "/ws"); // WebSocket 핸들러 등록
    @Bean
    public WebSocketHandler myHandler() {
        return new MyWebSocketHandler(); // 메시지 처리 로직을 가진 핸들러 구현

주로 STOMP (Simple Text Oriented Messaging Protocol) 를 사용하는 메시지 통신을 처리하고, WebSocket 메시지가 어떤 경로로 전송되고, 어떤 방식으로 처리될지 결정한다. 즉, WebSocket 연결이 이루어진 후 실제 메시지들이 서버와 클라이언트 사이에서 어떻게 라우팅되는지를 관리한다.

STOMP 프로토콜 기반 통신에 대해 아래의 처리를 담당한다.

  • 메시지 브로커 설정: WebSocket에서 들어오는 메시지를 라우팅하거나 브로드캐스팅하는 역할을 한다. 메시지 브로커는 클라이언트 간의 메시지 전달을 중계해준다.
  • STOMP 프로토콜 지원: Spring WebSocket에서는 STOMP라는 메시지 프로토콜을 지원하며, 이를 통해 클라이언트는 서버로 메시지를 보내고 특정 주제를 구독할 수 있다.
  • 메시지 라우팅: 메시지를 특정 주제(topic) 또는 큐(queue)로 라우팅하거나, 특정 클라이언트에게 메시지를 전달할 수 있다.
  • 동작 과정

  • 클라이언트가 WebSocket을 통해 서버에 연결된 후, STOMP 메시지를 주고받기 위한 경로가 설정된다.
  • 메시지 라우팅: 서버는 클라이언트의 메시지를 받아 적절한 구독자에게 메시지를 전달한다. 예를 들어, 사용자가 /app/chat 경로로 메시지를 보내면, 서버는 이 메시지를 처리하고 /topic/messages 구독자들에게 전송한다.
  • @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
        @Override
        public void configureMessageBroker(MessageBrokerRegistry config) {
            config.enableSimpleBroker("/topic", "/queue");  // 클라이언트 구독 가능 경로
            config.setApplicationDestinationPrefixes("/app");  // 클라이언트가 서버에 메시지를 보낼 때 사용할 경로
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            registry.addEndpoint("/ws").withSockJS();  // 클라이언트가 연결할 WebSocket 엔드포인트
    
    package com.example.springstompchat.controller;
    import com.example.springstompchat.model.ChatMessage;
    import org.springframework.messaging.handler.annotation.MessageMapping;
    import org.springframework.messaging.handler.annotation.SendTo;
    import org.springframework.stereotype.Controller;
    @Controller
    public class ChatController {
        @MessageMapping("/chat")
        @SendTo("/topic/messages")
        public ChatMessage sendMessage(ChatMessage message) {
            return message;
    

    세부 설명:

  • enableSimpleBroker("/topic", "/queue"): 메시지 브로커를 설정한다. 여기서 "/topic"과 "/queue"는 메시지가 전송되는 목적지다. 클라이언트는 이 경로를 구독해서 메시지를 받을 수 있다.
  • setApplicationDestinationPrefixes("/app"): 클라이언트가 서버로 메시지를 보낼 때 사용할 경로를 설정한다. 클라이언트는 /app/chat 같은 경로로 메시지를 보낼 수 있으며, 서버에서 이 메시지를 처리한다.
  • registerStompEndpoints: 클라이언트가 WebSocket에 연결하기 위한 엔드포인트를 설정한다. 예를 들어, 클라이언트는 /ws 경로로 연결을 시도할 수 있다.
  • 메시지 흐름

  • 클라이언트 -> 서버: 클라이언트가 /app/chat 경로로 메시지를 보내면, 서버는 이를 받아 처리한다.
  • 서버 -> 클라이언트: 서버는 처리한 메시지를 /topic/messages와 같은 주제로 구독한 클라이언트에게 브로드캐스팅한다.
  • 이 설정은 메시지 브로커를 이용해 WebSocket 통신에서 메시지를 처리하고 라우팅하는 핵심적인 역할을 담당한다. 이때 보안적인 부분은 신경 쓰지 않으며, 오직 메시지의 경로와 라우팅 규칙만 처리한다.

    2. @EnableWebSocketSecurity

    @EnableWebSecurity 설정은 http 프로토콜 통신에서 보안설정을 한다면 @EnableWebSocketSecurity는 ws 프로토콜 통신에서의 보안설정을 담당한다.

    연결된 후 WebSocket을 통해 주고받는 메시지에 대한 접근 권한을 제어한다. 예를 들어, 특정 사용자만 특정 경로의 메시지에 접근하도록 설정할 수 있다. 즉 STOMP 프로토콜 레벨에서의 권한 설정이 가능하다.

    간단 예제

    @Configuration
    public class WebSocketSecurityConfig {
        @Bean
        public AuthorizationManager<Message<?>> messageAuthorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
            messages
                    .nullDestMatcher().authenticated() 
                    .simpSubscribeDestMatchers("/user/queue/errors").permitAll() 
                    .simpDestMatchers("/app/**").hasRole("USER") 
                    .simpSubscribeDestMatchers("/user/**", "/topic/friends/*").hasRole("USER") 
                    .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() 
                    .anyMessage().denyAll(); 
            return messages.build();