Check auth while sending a message to a specific user by using STOMP and WebSocket in Spring

vdenotaris picture vdenotaris · Sep 3, 2014 · Viewed 9.1k times · Source

I'm developing a realtime notification system in Spring 4 by using a build-in Message Broker, and STOMP over WebSocket.

I would like to be able to send messages to a specific user, according with his username. In order to achieve this goal, I'm using the convertAndSendToUser method of org.springframework.messaging.simp.SimpMessagingTemplate class, as follows:

private final MessagingTemplate messagingTemplate;

@Autowired
public LRTStatusListener(SimpMessagingTemplate messagingTemplate) {
    this.messagingTemplate = messagingTemplate;
}


@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
    messagingTemplate
        .convertAndSendToUser(principal.getName(), "/horray", "Horray, " + principal.getName() + "!");
}

As configuration:

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic", "/queue", "/user");
    }

}

Client-side (via JavaScript), I should subscribe to a channel by specifing the username (according with another very similar question: Sending message to specific user on Spring Websocket).

stompClient.subscribe('/user/' + username + '/horray, ...) 

This last point sounds weird...

Supposing that I'm logged as w.white on my webapp, by subscribing:

stompClient.subscribe('/user/w.white/horray, ...)

... I will be able to see messages sent to w.white, and this is awesome... But subscribing:

stompClient.subscribe('/user/j.pinkman/horray, ...)

... I will be able to see also messages sent to j.pinkman, despide that I'm currently logged as w.white.

It is a way to overcome this problem?


Update

Below there is the log about the connection over WebSocket:

Opening Web Socket... 
Web Socket Opened... 
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000

<<< CONNECTED
user-name:w.white
heart-beat:0,0
version:1.1

connected to server undefined
Connected: CONNECTED
version:1.1
heart-beat:0,0
user-name:w.white

>>> SUBSCRIBE
id:sub-0
destination:/topic/lrt

>>> SUBSCRIBE
id:sub-1
destination:/user/lrt

Answer

vdenotaris picture vdenotaris · Sep 3, 2014

I found the solution.

First of all, it is important to know that the /user channel is already managed by Spring STOMP, and by the way, no registration is required.

So:

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic", "/queue");
}

Then, I setup the destination channel as /queue/horray:

@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
    messagingTemplate
        .convertAndSendToUser(principal.getName(), "/queue/horray", "Horray, " + principal.getName() + "!");
}

At last, on client:

stompClient.subscribe('/user/queue/horray', '...');

Now, it works fine! Messages are sent only to the specified recipient, according to the Principal fetched by the security context.