Pregunta

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.

¿Fue útil?

Solución

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

Otros consejos

As of Spring 5.x the correct method to override to attach the interceptor, if you're extending AbstractSecurityWebSocketMessageBrokerConfigurer, is customizeClientInboundChannel:

@Override
public void customizeClientInboundChannel(ChannelRegistration registration) {
    registration.interceptors(new TopicSubscriptionInterceptor());
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top