【问题标题】:Disconnect Websocket on server side based on a token passed from UI根据从 UI 传递的令牌断开服务器端的 Websocket
【发布时间】:2017-02-16 16:06:42
【问题描述】:

我的目标是将具有正确标头的浏览器客户端与服务器连接。我从 StompClient 传递这些标头。

我在标题中传递 token 的 UI 代码是

function connect() {
    var socket = new SockJS('/websocket/api/add');
    stompClient = Stomp.over(socket);
    stompClient.connect({"token" : "12345"}, function(frame) {
        setConnected(true);
        console.log('Connected: ' + frame);                
    });
}

在后端,我可以读取 ChannelInterceptorAdapter

的 preSend() 方法中的标头
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
    MessageHeaders headers = message.getHeaders();
    System.out.println("preSend : HEADERS : {}" + headers);
    return super.preSend(message, channel);
}

但是在这里我无法关闭 wesocket 会话。我们该怎么做?

我也能够关闭 websocket 会话,但我无法在 WebSocketHandlerDecorator

的 afterConnectionEstablished() 方法中接收标头
public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
    registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
        @Override
        public WebSocketHandler decorate(final WebSocketHandler handler) {
            return new WebSocketHandlerDecorator(handler) {
                @Override
                public void afterConnectionEstablished(final WebSocketSession session) throws Exception {   

                    session.close(CloseStatus.NOT_ACCEPTABLE);
                    super.afterConnectionEstablished(session);
                }
            };
        }
    });
    super.configureWebSocketTransport(registration);
}

有人可以指导我如何根据我们从服务器端的 UI 传递的标头关闭 websocketsession 吗?

【问题讨论】:

    标签: java spring-mvc websocket stomp


    【解决方案1】:

    您可以尝试在连接建立时通过消息将客户端的令牌发送给服务器,然后让服务器将该会话保存到映射中,其键为对应的令牌。

    因此,当您想通过其令牌关闭会话时,您可以使用令牌从该映射中查询会话。


    示例代码:

    使用令牌保存会话:

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        String messageToString = message.getPayload().toString();
        if (messageToString.startsWith("token=")) {
            tokenToSessionMapping.put(messageToString.substring("token=".length()));
        }
        // Other handling message code...
    }
    

    通过令牌关闭会话:

    WebSocketSession sessionByToken = tokenToSessionMapping.get(token);
    if (sessionByToken != null && sessionByToken.isOpen()) {
        sessionByToken.close(CloseStatus.NOT_ACCEPTABLE);
    }
    

    还有其他需要注意的事项:

    1. 因为tokenToSessionMapping 是静态的并且在会话之间共享。您应该使用线程安全的实现,例如 ConcurrentHashMap。

    2. 当会话关闭时,您最好从映射tokenToSessionMapping 中删除相应的条目。否则地图大小将继续增长。你可以通过覆盖方法afterConnectionClosed()来做到这一点。

      @Override
      public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
          Log.info("Socket session closed: {}", status.toString());
          String foundKey = null;
          for (Map.Entry<String, String> entry : tokenToSessionMapping.entrySet()) {
              if (Objects.equals(entry.getValue(), session)) {
                  foundKey = entry.getKey();
              }
          }
          if (foundKey != null) {
              tokenToSessionMapping.remove(foundKey);
          }
      }
      

    【讨论】:

    • 非常感谢您为我指明了正确的方向 :)
    猜你喜欢
    • 2015-04-17
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-16
    • 2013-02-03
    • 2014-09-24
    • 2017-08-28
    相关资源
    最近更新 更多