8


I am using spring-websocket and spring-messaging (version 4.2.2.RELEASE) to implement STOMP over websockets with a fully-featured broker (Apache ActiveMQ 5.10.0).
My clients are meant to SUBSCRIBE to destinations only - that is they should should not be able to SEND messages. Furthermore, I would like to implement a stricter control over what destinations my clients can subscribe to. In either case (that is when a client tries to send a message or subscribe to an invalid destination) I would like to be able to

  1. send an appropriate error, and/or
  2. close the websocket

Please note that all my destinations are forwarded to ActiveMQ. I thought that I could implement a ChannelInterceptor on the inbound channel, but looking at the API I cannot figure out how to achieve what I want. Is this possible, and what is the best way to go about validating client requests? My websocket configuration is below:

<websocket:message-broker
    application-destination-prefix="/app">
    <websocket:stomp-endpoint path="/pushchannel"/>
    <websocket:stomp-broker-relay relay-host="localhost"
        relay-port="61613" prefix="/topic"
        heartbeat-receive-interval="300000" heartbeat-send-interval="300000" />
    <websocket:client-inbound-channel>
        <websocket:interceptors>
            <bean class="MyClientMessageInterceptor"/>
        </websocket:interceptors>
    </websocket:client-inbound-channel>
</websocket:message-broker>
Nenad
  • 257
  • 3
  • 9

1 Answers1

0

You can write an inbound interceptor and send appropriate error message to the client.

public class ClientInboundChannelInterceptor extends ChannelInterceptorAdapter {

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;

@Override
public Message<?> preSend(Message message, MessageChannel channel) throws IllegalArgumentException{
    StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
    logger.debug("logging command " + headerAccessor.getCommand());
    try {
          //write your logic here
        } catch (Exception e){
            throw new MyCustomException();
        }
    }

}

UPDATE:

1) When you throw any exception from ClientInboundChannelInterceptor, it will be sent as ERROR frame, you don't have to do anything special.

2) I am not sure about closing the connection, but doing something like creating DISCONNECT headers and sending it should work(I will try to test this and update the answer).

SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.DISCONNECT);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);

template.convertAndSendToUser(destination,new HashMap<>(),headerAccessor.getMessageHeaders());

You have one of the following options to send error while subscribing.

1) Throw exception from ClientInboundChannelInterceptor.

2) In your Handler/Controller, add @SubscribeMapping and return the frame.

@SubscribeMapping("your destination")
public ConnectMessage handleSubscriptions(@DestinationVariable String userID, org.springframework.messaging.Message message){
    // this is my custom class
    ConnectMessage frame= new ConnectMessage();
    // write your logic here
    return frame;
}

frame will be sent directly to client.

Karthik
  • 4,950
  • 6
  • 35
  • 65
  • That is a good idea, however, 1) how do you use SimpMessagingTemplate to send a STOMP ERROR frame? and 2) how do you tear-offf/close the websocket? – Nenad Mar 07 '16 at 00:45
  • @Nenad updated the answer, try the second part and let me know if it works. – Karthik Mar 07 '16 at 07:25
  • @Kathrik if I throw an exception than I would be giving up the control of the thread and wouldn't be able to do a disconnect. Do you know if there is a way of sending ERROR frame without throwing an exception? – Nenad Mar 07 '16 at 13:58
  • Looking at your sample and the API it seems that you can send an ERROR frame without throwing an exception: you can use `StompHeaderAccessor.create(StompCommand.ERROR)` and then send it using SimpMessagingTemplate. I will see if that works... – Nenad Mar 07 '16 at 14:16
  • @Kathrik in 2) of your answer update what do you set as `destination`? My understanding Is that destination is a STOMP destination that the client subscribed to? What should I use as a destination then when sending an ERROR frame for a subscription request that is invalid? – Nenad Mar 07 '16 at 16:26