Javier Moreno Garcia
Javier Moreno Garcia

Reputation: 602

WebSocket closed before HttpSessionListener.sessionDestroyed is called

I am implementing a Spring Boot + WebSocket + SockJS application and have a doubt about how to handle the HTTP session/ Websocket relation.

Basically I would like to be able to inform the user that his session has been invalidated (because of a timeout or because of having logged in from another location). For that I wanted to put in his own socket a certain message just before the framework closes it.

I turned to an http listener but the problem I have is that by the time HttpSessionListener.sessionDestroyed() is called I can see the socket has been already closed by the framework (not due to some other event like the user closing the browser).

Has anybody any idea about how to achieve this?

I have a really simple Websocket config and am running with Spring Boot defaults.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.setMessageSizeLimit(10000000);
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app/");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/myEndPoint").withSockJS();
    }

}

Security part:

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        applySecurity(messages);
    }

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }

    private static void applySecurity(MessageSecurityMetadataSourceRegistry messages) {

        messages.nullDestMatcher().authenticated() //
                .simpDestMatchers("/app/**").authenticated().simpSubscribeDestMatchers("/user/reply").authenticated()
                .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll().anyMessage().denyAll();

    }
}  

My Http listener would be like this:

    return new HttpSessionListener() {

        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            simpMessagingTemplate.convertAndSendToUser(....);
        }

        @Override
        public void sessionCreated(HttpSessionEvent se) {
            // no need to do anything when a session is created
        }
    };

UPDATE:

Spring-session handles issues like this one and many others.

Upvotes: 2

Views: 2630

Answers (2)

Darshan Mehta
Darshan Mehta

Reputation: 30809

HttpSession and Websocket session are two different kind of sessions. HttpSession is created when client accesses the url and completes Handshake whereas Websocket session is created when client sends subscribe request.

Websocket session is wrapped under HttpSession. If HttpSession gets timed out or invalidated then underlying Websocket session also gets disconnected, however, vice versa is not true.

Coming to your point of configuring listener for Websocket session, HttpSession listener won't be able to listen for Websocket session events. For such events, we need to define a class which extends org.springframework.web.socket.messaging.SubProtocolWebSocketHandler class and override afterConnectionEstablished and afterConnectionClosed methods. Have a look at Javadoc here.

Also, here is an example that listens for Spring websocket disconnect events. You need to configure something similar to this.

Upvotes: 2

user207421
user207421

Reputation: 310850

An HTTP session is supposed to survive the connection. That's what it's for. Multiple connections, same session. The session should not expire while there are active connections.

Upvotes: 0

Related Questions