如何使用Spring WebSocket向STOMP客户端发送ERROR消息? [英] How to send ERROR message to STOMP clients with Spring WebSocket?

查看:1937
本文介绍了如何使用Spring WebSocket向STOMP客户端发送ERROR消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Spring的STOMP而不是WebSocket实现,使用功能齐全的ActiveMQ代理。当用户 SUBSCRIBE 到某个主题时,在成功订阅之前,他们必须通过一些权限逻辑。我正在使用ChannelInterceptor来应用权限逻辑,如下所示:

I am using Spring's STOMP over WebSocket implementation with a full-featured ActiveMQ broker. When users SUBSCRIBE to a topic, there is some permissions logic that they must pass through before being successfully subscribed. I am using a ChannelInterceptor to apply the permissions logic, as configured below:

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
  }
}

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

When clients who do not have adequate permissions attempt to subscribe to a restricted topic, they never actually receive any messages from the topic BUT are also not notified of the exception that was thrown which rejected their subscription. Instead, the client is handed back a dead subscription that the ActiveMQ broker knows nothing about. (Normal, adequately-permissioned client interactions with the STOMP endpoint and topics work just as expected.)

我已尝试订阅 users / {subscribingUsername } / queue / errors 并且在成功连接后使用我的Java测试客户端只是简单的 users / queue / errors 但是我到目前为止无法从传递到客户端的服务器获得有关订阅异常的错误消息。这显然不太理想,因为客户从未被告知他们被拒绝访问。

I have tried subscribing to users/{subscribingUsername}/queue/errors and just plain users/queue/errors with my Java test client after it is successfully connected, but I have thus far been unable to get sort of error message about the subscription exception from the server delivered to the client. This is obviously less than ideal since clients are never notified that they've been denied access.

推荐答案

你不能只是扔来自 clientInboundChannel MySubscriptionInterceptor 的异常,因为最后一个是 ExecutorSubscribableChannel ,因此是 async ,来自这些线程的任何异常都会在日志中结束,并且会向调用者重新抛出 - StompSubProtocolHandler.handleMessageFromClient

You can't just throw exception from the MySubscriptionInterceptor on the clientInboundChannel, because the last one is ExecutorSubscribableChannel, therefore is async and any exceptions from those threads are end up in the logs with any re-throw to the caller - StompSubProtocolHandler.handleMessageFromClient.

但你可以做的是像 clientOutboundChannel ,并像使用它一样这个:

But what you can do there is something like clientOutboundChannel and use it like this:

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

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

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

Another option to consider is Annotation mapping:

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

    @MessageExceptionHandler
    @SendToUser("/queue/error")
    public String handleException(IllegalArgumentException ex) {
        return "Got error: " + ex.getMessage();
    }

这篇关于如何使用Spring WebSocket向STOMP客户端发送ERROR消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆