如何使用 Spring WebSocket 向 STOMP 客户端发送错误消息?

2024-02-06

我正在使用 Spring 的 STOMP over WebSocket 实现和功能齐全的 ActiveMQ 代理。当用户SUBSCRIBE对于一个主题,有一些权限逻辑,必须经过一些权限逻辑,才能成功订阅。我正在使用 ChannelInterceptor 来应用权限逻辑,配置如下:

WebSocketConfig.java:

@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

  @Override
  public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableStompBrokerRelay("/topic", "/queue")
      .setRelayHost("relayhost.mydomain.com")
      .setRelayPort(61613);
  }

  @Override
  public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.setInterceptors(new MySubscriptionInterceptor());
  }


}

WebSocketSecurityConfig.java:

public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

  @Override
  protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
    messages
      .simpSubscribeDestMatchers("/stomp/**").authenticated()
      .simpSubscribeDestMatchers("/user/queue/errors").authenticated()
      .anyMessage().denyAll();
  }

}

MySubscriptionInterceptor.java:

public class MySubscriptionInterceptor extends ChannelInterceptorAdapter {

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

    StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
    Principal principal = headerAccessor.getUser();

    if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
      checkPermissions(principal);
    }

    return message;
  }

  private void checkPermissions(Principal principal) {
    // apply permissions logic
    // throw Exception permissions not sufficient
  }
}

当没有足够权限的客户端尝试订阅受限主题时,他们实际上从未收到来自该主题的任何消息,但也不会收到拒绝其订阅的抛出异常的通知。相反,客户端会收到一个 ActiveMQ 代理一无所知的死订阅。 (正常的、获得充分许可的客户端与 STOMP 端点和主题的交互按预期工作。)

我尝试过订阅users/{subscribingUsername}/queue/errors简单地说users/queue/errors成功连接后与我的 Java 测试客户端一起使用,但到目前为止我无法从服务器传递到客户端获取有关订阅异常的错误消息。这显然不太理想,因为客户永远不会收到他们被拒绝访问的通知。


你不能只是抛出异常MySubscriptionInterceptor on the clientInboundChannel,因为最后一个是ExecutorSubscribableChannel,因此是async这些线程的任何异常最终都会记录在日志中,并重新抛出给调用者 -StompSubProtocolHandler.handleMessageFromClient.

但你能做的就是clientOutboundChannel并像这样使用它:

StompHeaderAccessor headerAccessor = StompHeaderAccessor.create(StompCommand.ERROR);
headerAccessor.setMessage(error.getMessage());

clientOutboundChannel.send(MessageBuilder.createMessage(new byte[0], headerAccessor.getMessageHeaders()));

另一个需要考虑的选项是注释映射:

    @SubscribeMapping("/foo")
    public void handleWithError() {
        throw new IllegalArgumentException("Bad input");
    }

    @MessageExceptionHandler
    @SendToUser("/queue/error")
    public String handleException(IllegalArgumentException ex) {
        return "Got error: " + ex.getMessage();
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Spring WebSocket 向 STOMP 客户端发送错误消息? 的相关文章

随机推荐