2015-11-16 19 views
12

Sto utilizzando Spring STOMP su un'implementazione WebSocket con un broker ActiveMQ completo. Quando gli utenti SUBSCRIBE a un argomento, c'è qualche logica di permessi che devono passare prima di essere iscritti con successo. Sto usando un ChannelInterceptor di applicare la logica delle autorizzazioni, come configurato di seguito:Come inviare un messaggio ERROR ai client STOMP con 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 
    } 
} 

Quando i client che non dispongono di autorizzazioni adeguate tentano di iscriversi a un argomento limitato, non ricevono mai alcun messaggio dall'argomento, MA non ricevono alcuna notifica dell'eccezione generata che ha rifiutato l'abbonamento. Invece, il client viene restituito un abbonamento morto che il broker ActiveMQ non sa nulla. (Normale, le interazioni dei clienti in modo adeguato-gestite le autorizzazioni con l'endpoint STOMP e argomenti funzionare come previsto.)

ho cercato la sottoscrizione di users/{subscribingUsername}/queue/errors e semplicemente users/queue/errors con il mio client di test di Java dopo che è stato collegato con successo, ma non ho finora stato impossibile ottenere una sorta di messaggio di errore sull'eccezione di sottoscrizione dal server consegnato al client. Questo è ovviamente meno ideale dato che i client non vengono mai informati che gli è stato negato l'accesso.

risposta

5

Non si può semplicemente gettare deroga al MySubscriptionInterceptor sul clientInboundChannel, perché l'ultima è ExecutorSubscribableChannel, quindi è async e le eventuali eccezioni da quei fili si finisce nei registri con qualsiasi ri-tiro al chiamante - StompSubProtocolHandler.handleMessageFromClient .

Ma cosa si può fare ci sia qualcosa come clientOutboundChannel e usarlo in questo modo:

StompHeaderAccessor headerAccessor = StompHeaderAccessor.create(StompCommand.ERROR); 
headerAccessor.setMessage(error.getMessage()); 

clientOutboundChannel.send(MessageBuilder.createMessage(new byte[0], headerAccessor.getMessageHeaders())); 

Un'altra opzione da considerare è la mappatura della nota:

@SubscribeMapping("/foo") 
    public void handleWithError() { 
     throw new IllegalArgumentException("Bad input"); 
    } 

    @MessageExceptionHandler 
    @SendToUser("/queue/error") 
    public String handleException(IllegalArgumentException ex) { 
     return "Got error: " + ex.getMessage(); 
    } 
+0

Grazie per questo @Artem, ho dato un tentativo. Sfortunatamente, quando un'eccezione viene lanciata nel metodo '@ SubscribeMapping' e gestita dal metodo' @ MessageExceptionHandler', un messaggio viene inviato alla coda degli errori del client, MA la loro sottoscrizione viene comunque inoltrata al broker e il client continua a ricevere i messaggi successivi dall'argomento. – hartz89

+1

Quindi, prova a usare direttamente 'send' per' clientOutboundChannel' da '@ MessageExceptionHandler'. –

+0

@ArtemBilan potresti spiegare come ottenere OutboundChannel? Fatto una domanda: http://stackoverflow.com/questions/39641477/send-stomp-error-from-spring-websocket-program –

Problemi correlati