【问题标题】:Using Spring WebSocket's SimpMessagingTemplate with multi endpoint configuration将 Spring WebSocket 的 SimpMessagingTemplate 与多端点配置一起使用
【发布时间】:2017-08-29 16:55:03
【问题描述】:

我正在使用带有 SockJS、STOMP 和 SimpleBrokerMessageHandler 的 Spring 4.3.5 和 WebSocket。

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

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

最后我有了三个客户端,每个都连接到一个不同的端点。 然而,他们都订阅了“相同”的频道地址,即 /topic/messages

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

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

之后我有两个问题:

  1. 有没有办法“隔离” Web Socket 端点,使消息不会传播到所有端点?
  2. 为什么这里会发生这种情况?

我做了一些调查(堆转储分析),发现我的配置有:

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

所以我想知道,这种在所有端点上传播的消息是否是 SimpleBrokerMessageHandler 或 SimpMessagingTemplate 的“功能”。

【问题讨论】:

  • 我也有类似的问题。你能回忆一下你是如何解决这个问题的吗?
  • 嗨,很遗憾我们没有。我们接受现实 - 这是概念应用程序的证明。虽然我还是很好奇这背后的原因是什么。
  • 原因取决于您的配置。可能所有的客户都订阅了同一个主题。相反,他们应该订阅各自的队列
  • 是的,订阅了同一个主题,尽管我认为不同名称的端点之间存在主题隔离。
  • 不,消息不能那样工作。可以通过专用队列进行隔离。

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


【解决方案1】:

感谢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 表单以租户 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 实现 org.springframework.security.core.Authentication 具有附加的tenantId 属性,该属性由自定义弹簧安全过滤器/身份验证方法中未提及的附加代码填充:

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

当然这涉及到服务器发送的每条消息都应该以正确的tenant-id为前缀:MessagingService.convertAndSend("[tenant-id]/[url-of-queue]", messagePayload)

【讨论】:

    猜你喜欢
    • 2017-09-24
    • 1970-01-01
    • 2015-11-14
    • 2021-09-16
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多