I need to control connection/disconnection and subscriptions/unsubscriptions of stomp clients in my websocket spring server. This is the main configuration class:
@Configuration
@ComponentScan(basePackages = "com.test")
@EnableWebSocketMessageBroker
@EnableWebMvc
public class Config extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
config.setApplicationDestinationPrefixes("/app");
config.setUserDestinationPrefix("/user");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp").setAllowedOrigins("*").addInterceptors(getInterceptot());
}
private HandshakeInterceptor getInterceptot() {
return new HandshakeInterceptor(){
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
return true; //TODO
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}
};
}
}
I could intercept the connection event with beforeHandshake
method, but I don't know if this is the best way.
Moreover I need to check all disconnections, subscription and unsubscriptions, I tried to use @SubscribeMapping("/**")
annotation but it doesn't work for me.
I tried this:
@Component
public class StompEventListener {
@EventListener
private void handleSessionConnected(SessionConnectEvent event) {
}
@EventListener
private void handleSessionDisconnect(SessionDisconnectEvent event) {
}
@EventListener
private void handleSessionSubscribeEvent(SessionSubscribeEvent event) {
}
@EventListener
private void handleSessionUnsubscribeEvent(SessionUnsubscribeEvent event) {
}
}
It works, but I need to intercept this request and I should deny/grant all operations, for example I can decide to deny the connection but with @EventListener
I cannot do this because it is called after the connection.
With a HandshakeInterceptor
you won't be able to get CONNECT / DISCONNECT frames. You have to implement a ChannelInterceptor (or extend ChannelInterceptorAdapter) and add it to the clientInboundChannel
. The preSend
method allows you to add your logic before the message is processed:
public class FilterChannelInterceptor extends ChannelInterceptorAdapter {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand()) {
// Your logic
}
return message;
}
}
Check out the Spring Security interceptor, which might be a good starting point: https://github.com/spring-projects/spring-security/blob/master/messaging/src/main/java/org/springframework/security/messaging/web/csrf/CsrfChannelInterceptor.java