java Spring websocket 发送给特定的人

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43198292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 07:11:28  来源:igfitidea点击:

Spring websocket send to specific people

javaspringspring-securityspring-websocket

提问by BiJ

I have added custom token based authentication for my spring-web app and extending the same for spring websocket as shown below

我为我的 spring-web 应用程序添加了基于自定义令牌的身份验证,并为 spring websocket 扩展了相同的身份验证,如下所示

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;
            }
        });
      }
}

The client side code to connect to the socket is

连接到套接字的客户端代码是

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);
        });
    });

And from my controller I am sending message as

从我的控制器我发送消息

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

For the auth token 12345tokenthe user name is user1. But when I send a message to user1, its not received at the client end. Is there anything I am missing with this?

对于身份验证令牌12345token,用户名是user1。但是当我向 发送消息时user1,它没有在客户端收到。有什么我遗漏的吗?

回答by Oreste Viron

In your Websocket controller you should do something like this :

在您的 Websocket 控制器中,您应该执行以下操作:

@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);
    }
}

On the client side, your user should subscribe to topic /user/queue/reply.

在客户端,您的用户应该订阅主题 /user/queue/reply。

You must also add some destination prefixes :

您还必须添加一些目的地前缀:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

When your server receive a message on the /app/hello queue, it should send a message to the user in your dto. User must be equal to the user's principal.

当您的服务器在 /app/hello 队列上收到一条消息时,它应该向您的 dto 中的用户发送一条消息。用户必须等于用户的委托人。

I think the only problem in your code is that your "/user" is not in your destination prefixes. Your greetings messages are blocked because you sent them in a queue that begin with /user and this prefixe is not registered.

我认为您的代码中唯一的问题是您的“/user”不在您的目标前缀中。您的问候消息被阻止,因为您将它们发送到以 /user 开头的队列中,并且此前缀未注册。

You can check the sources at git repo : https://github.com/simvetanylen/test-spring-websocket

您可以在 git repo 中查看源代码:https: //github.com/simvetanylen/test-spring-websocket

Hope it works!

希望它有效!

回答by Angelo Immediata

In my previous project I sent messages to one specific user; in detail I wrote the following:

在我之前的项目中,我向一个特定用户发送了消息;我详细写了以下内容:

CLIENT SIDE:

客户端

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 SIDE

服务器端

Spring websocket listener:

Spring websocket 侦听器:

@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 message sender:

Spring websocket 消息发送方:

@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);
    }

I hope it's useful

我希望它有用