使用Spring WebSocket的SimpMessagingTemplate和多端点配置

时间:2017-04-04 13:04:56

标签: java spring websocket spring-websocket spring-4

我正在使用Spring 4.3.5和WebSocket与SockJS,STOMP和SimpleBrokerMessageHandler。

在我的应用程序中,我有三个独立的WebSocket端点在不同的地址上运行: / endPointA,/ ednpointB,/ endpointC 更具体地说,我有三个单独的配置类,用@Configuration @EnableWebSocketMessageBroker注释注释。

我还有一个拥有@Autowired SimpMessagingTemplate的类。

最后我有三个客户端,每个客户端连接到一个不同的EndPoint。 但是,所有这些都订阅了“相同”的频道地址,即 / topic / messages

  • ClientOne已连接 endpointA
  • ClientTwo已连接 endpointB
  • ClientThree已连接 endpointC

当我使用 SimpMessagingTemplate / topic / messages 发送内容时,所有客户端都会收到此消息。

之后我有两个问题:

  1. 有没有办法“隔离”Web Socket端点,以便消息不会传播到所有端点?
  2. 为什么这实际发生在这里?
  3. 我做了一些调查(堆转储分析),我发现对于我的配置我有:

    • SimpMessagingTemplate 的三个实例,但是我总是使用相同的一个实例来发送消息(因为@Autowire - 另外我正在打印SimpMessagingTemplate.toString())。
    • SimpleBrokerMessageHandler
    • 的一个实例
    • SockJsWebSocketHandler
    • 的三个实例

    所以我想知道,如果这个消息在所有endpoits上的传播是SimpleBrokerMessageHandler或SimpMessagingTemplate的“特性”。

1 个答案:

答案 0 :(得分:2)

this thread的帮助下,我在多租户应用程序中遇到了相同的问题:

我的websocket端点是:ws://127.0.0.1/my-context-app/ws ,java配置文件为:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

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

我的websocket队列url形式以tenant-id为前缀:/[tenant-id]/[url-of-queue]

每个客户端都订阅自己的租户ID。由于WebSocketSecurityConfig.configureInbound(MessageSecurityMetadataSourceRegistry)方法和具有'websocket-queue-subscription-security-check'方法的自定义spring bean,它无法预订另一个客户端的队列:

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
          .simpSubscribeDestMatchers("/**")
          .access("@customWSSecurityCheck.isSubscriptionAllowed(authentication, message)");
    }

}

我的名为customWSSecurityCheck的自定义bean检查是否允许经过身份验证的用户在队列上进行订阅。请记住,CustomAuthentication用附加的tenantId属性实现org.springframework.security.core.Authentication,该属性由在自定义spring安全过滤器/身份验证方法上未提及的其他代码填充:

@Bean()
public class CustomWSSecurityCheck {

    public boolean isSubscriptionAllowed(CustomAuthentication authentication, Message message) {

       StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
       String url = sha.getDestination().substring(1);
       String tenantId = url.substring(0, url.indexOf("/"));

       return tenantId.equals(authentication.getTenantId());
    }
}

当然,这涉及到服务器发送的每条消息均应带有正确的租户ID:MessagingService.convertAndSend("[tenant-id]/[url-of-queue]", messagePayload)