web-dev-qa-db-de.com

Frühlings-Websocket senden an bestimmte Personen

Ich habe eine benutzerdefinierte tokenbasierte Authentifizierung für meine Spring-Web-App hinzugefügt

public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue");
        config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket").setAllowedOrigins("*").withSockJS();
    }

    @Override
      public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.setInterceptors(new ChannelInterceptorAdapter() {

            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {

                StompHeaderAccessor accessor =
                    MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    String jwtToken = accessor.getFirstNativeHeader("Auth-Token");
                        if (!StringUtils.isEmpty(jwtToken)) {
                            Authentication auth = tokenService.retrieveUserAuthToken(jwtToken);
                            SecurityContextHolder.getContext().setAuthentication(auth);
                            accessor.setUser(auth);
                            //for Auth-Token '12345token' the user name is 'user1' as auth.getName() returns 'user1'
                        }
                }

                return message;
            }
        });
      }
}

Der clientseitige Code für die Verbindung zum Socket lautet

var socket = new SockJS('http://localhost:8080/gs-guide-websocket');
    stompClient = Stomp.over(socket);
    stompClient.connect({'Auth-Token': '12345token'}, function (frame) {
        stompClient.subscribe('/user/queue/greetings', function (greeting) {
            alert(greeting.body);
        });
    });

Und von meinem Controller schicke ich eine Nachricht als 

messagingTemplate.convertAndSendToUser("user1", "/queue/greetings", "Hi User1");

Für das Auth-Token 12345token lautet der Benutzername user1. Wenn ich jedoch eine Nachricht an user1 sende, wird diese nicht beim Client empfangen. Gibt es etwas, was mir fehlt?

6
BiJ

In Ihrem Websocket-Controller sollten Sie Folgendes tun:

@Controller
public class GreetingController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @MessageMapping("/hello")
    public void greeting(Principal principal, HelloMessage message) throws  Exception {
        Greeting greeting = new Greeting();
        greeting.setContent("Hello!");
        messagingTemplate.convertAndSendToUser(message.getToUser(), "/queue/reply", greeting);
    }
}

Auf der Clientseite sollte Ihr Benutzer das Thema/den Benutzer/die Warteschlange/die Antwort abonnieren.

Sie müssen auch einige Zielpräfixe hinzufügen:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue" ,"/user");
        config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user");
    }
/*...*/
}

Wenn Ihr Server eine Nachricht in der Warteschlange/app/hello empfängt, sollte er dem Benutzer in Ihrem dto eine Nachricht senden. Der Benutzer muss dem Auftraggeber des Benutzers entsprechen.

Ich denke, das einzige Problem in Ihrem Code ist, dass Ihr "/ Benutzer" nicht in Ihren Zielpräfixen ist. Ihre Begrüßungsnachrichten werden blockiert, weil Sie sie in einer Warteschlange gesendet haben, die mit/user beginnt und dieses Präfix nicht registriert ist.

Sie können die Quellen bei git repo überprüfen: https://github.com/simvetanylen/test-spring-websocket

Hoffe, es funktioniert!

12
Oreste Viron

In meinem vorherigen Projekt habe ich Nachrichten an einen bestimmten Benutzer gesendet. im detail schrieb ich folgendes:

CLIENT SEITE :

function stompConnect(notificationTmpl) 
{
    var socket = new SockJS('/comm-svr');
    stompClient = Stomp.over(socket);
    var theUserId 
    stompClient.connect({userId:theUserId}, function (frame) {
            debug('Connected: ' + frame);
            stompClient.subscribe('/topic/connect/'+theUserId, function (data)                   {
//Handle data
              } 
        });
}

SERVER SEITE

Spring Websocket Listener:

@Component
public class WebSocketSessionListener
{
    private static final Logger logger = LoggerFactory.getLogger(WebSocketSessionListener.class.getName());
    private List<String> connectedClientId = new ArrayList<String>();

    @EventListener
    public void connectionEstablished(SessionConnectedEvent sce)
    {
        MessageHeaders msgHeaders = sce.getMessage().getHeaders();
        Principal princ = (Principal) msgHeaders.get("simpUser");
        StompHeaderAccessor sha = StompHeaderAccessor.wrap(sce.getMessage());
        List<String> nativeHeaders = sha.getNativeHeader("userId");
        if( nativeHeaders != null )
        {
            String userId = nativeHeaders.get(0);
            connectedClientId.add(userId);
            if( logger.isDebugEnabled() )
            {
                logger.debug("Connessione websocket stabilita. ID Utente "+userId);
            }
        }
        else
        {
            String userId = princ.getName();
            connectedClientId.add(userId);
            if( logger.isDebugEnabled() )
            {
                logger.debug("Connessione websocket stabilita. ID Utente "+userId);
            }
        }
    }

    @EventListener
    public void webSockectDisconnect(SessionDisconnectEvent sde)
    {
        MessageHeaders msgHeaders = sde.getMessage().getHeaders();
        Principal princ = (Principal) msgHeaders.get("simpUser");
        StompHeaderAccessor sha = StompHeaderAccessor.wrap(sde.getMessage());
        List<String> nativeHeaders = sha.getNativeHeader("userId");
        if( nativeHeaders != null )
        {
            String userId = nativeHeaders.get(0);
            connectedClientId.remove(userId);
            if( logger.isDebugEnabled() )
            {
                logger.debug("Connessione websocket stabilita. ID Utente "+userId);
            }
        }
        else
        {
            String userId = princ.getName();
            connectedClientId.remove(userId);
            if( logger.isDebugEnabled() )
            {
                logger.debug("Connessione websocket stabilita. ID Utente "+userId);
            }
        }
    }

    public List<String> getConnectedClientId()
    {
        return connectedClientId;
    }
    public void setConnectedClientId(List<String> connectedClientId)
    {
        this.connectedClientId = connectedClientId;
    }
}

Spring Websocket Nachrichtensender:

@Autowired
    private SimpMessagingTemplate msgTmp;
    private void propagateDvcMsg( WebDeviceStatusInfo device )
    {
        String msg = "";
        String userId =((Principal)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getName()
        msgTmp.convertAndSend("/topic/connect"+userId, msg);
    }

Ich hoffe es ist nützlich

1