Я использую реализацию 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 после того, как он был успешно подключен, но до сих пор мне не удалось получить сообщение об ошибке подписки с сервера, доставленного клиенту. Это явно далеко не идеально, поскольку клиентов никогда не уведомляют об отказе в доступе.