I'm implementing a version of the stock application where the server able to reject topic subscription for certain topic based on the user rights. Is there a way in spring-websocket to do this?
For example:
In the stock example project we have price topic for 3 instrument: Apple, Microsoft, Google And have two user: User1, User2
User1 should have access to Apple and Microsoft User2 should have access to Google only
If User1 subscribe to Google he should got rejected response, and message shouldn't broadcast to him afterwards.
Thanks to Rossen Stoyanchev answer on github I was manage to solve this by adding interceptor to the inbound channel. Changes needed in the spring-websocket-portfolio demo application is the following:
Change websocket configuration:
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new TopicSubscriptionInterceptor());
}
And the interceptor was something like this:
public class TopicSubscriptionInterceptor extends ChannelInterceptorAdapter {
private static Logger logger = org.slf4j.LoggerFactory.getLogger(TopicSubscriptionInterceptor.class);
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
Principal userPrincipal = headerAccessor.getUser();
if(!validateSubscription(userPrincipal, headerAccessor.getDestination()))
{
throw new IllegalArgumentException("No permission for this topic");
}
}
return message;
}
private boolean validateSubscription(Principal principal, String topicDestination)
{
if (principal == null) {
// unauthenticated user
return false;
}
logger.debug("Validate subscription for {} to topic {}",principal.getName(),topicDestination);
//Additional validation logic coming here
return true;
}
}