根据从 UI 传递的令牌断开服务器端的 Websocket

Posted

技术标签:

【中文标题】根据从 UI 传递的令牌断开服务器端的 Websocket【英文标题】:Disconnect Websocket on server side based on a token passed from UI 【发布时间】: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 吗?

【问题讨论】:

【参考方案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);

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

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

    当会话关闭时,您最好从映射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);
        
    
    

【讨论】:

非常感谢您为我指明了正确的方向 :)

以上是关于根据从 UI 传递的令牌断开服务器端的 Websocket的主要内容,如果未能解决你的问题,请参考以下文章

Swagger UI 将身份验证令牌传递给标头中的 API 调用

如果应用断开互联网,如何再次获取设备令牌(APNS)?

Springboot:将从swagger UI捕获的JWT令牌自动传递给下游(服务到服务)API调用

无法从服务器端的请求中获取令牌

公司linux使用Ubuntu的服务器版,使用ssh连接一会就断开,需要将本地连接断开,重启才能连接上。一会还断

从令牌服务器(身份服务器 4)进行身份验证后重定向到客户端的相同 URL