Używam Springa STOMP nad implementacją WebSocket z pełnoprawnym brokerem ActiveMQ. Kiedy użytkownicy mają SUBSCRIBE
tematu, istnieje pewna logika uprawnień, którą muszą przejść, zanim zostanie pomyślnie zasubskrybowana. Używam ChannelInterceptor zastosować logikę uprawnień, jak skonfigurowany poniżej:Jak wysłać komunikat ERROR do klientów STOMP za pomocą Spring WebSocket?
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
}
}
Gdy klienci, którzy nie mają odpowiednich uprawnień, próbują zasubskrybować ograniczony temat, nigdy nie otrzymują wiadomości od tematu, ale nie są również powiadamiani o zgłoszonym wyjątku, który odrzucił ich subskrypcję. Zamiast tego klient otrzymuje niedziałającą subskrypcję, o której broker ActiveMQ nic nie wie. (Normalne, odpowiednio dozwolone interakcje klienta z punktem końcowym STOMP i tematy działają zgodnie z oczekiwaniami).
Próbowałem subskrybować users/{subscribingUsername}/queue/errors
i po prostu users/queue/errors
z moim klientem testowym Java po pomyślnym podłączeniu, ale do tej pory miałem nie można uzyskać komunikatu o błędzie dotyczącego wyjątku subskrypcji z serwera dostarczonego do klienta. Jest to oczywiście mniej niż idealne, ponieważ klienci nigdy nie otrzymują powiadomienia, że odmówiono im dostępu.
Dzięki za tym @Artem, dałem go próba. Niestety, gdy wyjątek jest zgłaszany w metodzie '@ SubscribeMapping' i obsługiwany przez metodę' @ MessageExceptionHandler', komunikat jest wysyłany do kolejki błędów klienta, ALE ich subskrypcja jest nadal przekazywana do brokera, a klient nadal otrzymuje kolejne wiadomości z tematu. – hartz89
Spróbuj więc użyć bezpośredniego 'wyślij' do' clientOutboundChannel' z tego '@ MessageExceptionHandler'. –
@ArtemBilan możesz wyjaśnić, jak uzyskać OutboundChannel? Zadaje pytanie: http://stackoverflow.com/questions/39641477/send-stomp-error-from-spring-websocket-program –