Я использую Spring STOMP через реализацию WebSocket с полнофункциональным брокером ActiveMQ. Когда пользователи SUBSCRIBE
относятся к теме, существует некоторая логика разрешений, которую они должны пройти до того, как будут успешно подписаны. Я использую ChannelInterceptor для применения логики разрешений, как описано ниже:
WebSocketConfig.java:
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp")
.setAllowedOrigins("*")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("relayhost.mydomain.com")
.setRelayPort(61613);
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new MySubscriptionInterceptor());
}
}
WebSocketSecurityConfig.java:
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpSubscribeDestMatchers("/stomp/**").authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").authenticated()
.anyMessage().denyAll();
}
}
MySubscriptionInterceptor.java:
public class MySubscriptionInterceptor extends ChannelInterceptorAdapter {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
Principal principal = headerAccessor.getUser();
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
checkPermissions(principal);
}
return message;
}
private void checkPermissions(Principal principal) {
// apply permissions logic
// throw Exception permissions not sufficient
}
}
Когда клиенты, у которых нет соответствующих прав, пытаются подписаться на тему с ограниченным доступом, они фактически не получают никаких сообщений из темы, но также не уведомляются об исключении, которое было отклонено, что отклонило их подписку. Вместо этого клиент получает мертвую подписку, о которой брокер ActiveMQ ничего не знает. (Нормальные, адекватно разрешенные клиентские взаимодействия с конечной точкой STOMP и темами работают так, как ожидалось.)
Я пробовал подписаться на users/{subscribingUsername}/queue/errors
и просто просто users/queue/errors
с моим тестовым клиентом Java после того, как он успешно подключен, но до сих пор мне не удалось получить сообщение об ошибке об исключении подписки с сервера, доставленного на клиент. Это, очевидно, меньше, чем идеальный, поскольку клиенты никогда не уведомляются о том, что им отказали в доступе.