I have a simple web socket application that uses stomp. when a user visits a page it will automatically make a stomp connection to the server. The user is authenticated via spring security. When the user closes the browser i want the user to automatically logout. To do this I create a listener to listen for SessionDisconnectEvent. The problem is I don't have a handle to the httpSession associated with the websocket session? Is there a want to get the httpsession from the websocket session?
here's my code:
<websocket:message-broker application-destination-prefix="/test">
<websocket:stomp-endpoint path="/sbapp">
<websocket:handshake-interceptors>
<bean class="com.sample.HttpSessionIdHandshakeInterceptor"></bean>
</websocket:handshake-interceptors>
<websocket:sockjs />
</websocket:stomp-endpoint>
<websocket:stomp-broker-relay prefix="/topic,/queue,/user" relay-host="localhost" relay-port="61613"/>
</websocket:message-broker>
here's my websocket session listener:
@Component
public class StompDisconnectListener implements ApplicationListener<SessionDisconnectEvent>{
@Override
public void onApplicationEvent(SessionDisconnectEvent event) {
System.out.println("Stomp disconnect: " + event.getSessionId());
}
}
I need a way such that when i get get a disconnect event I get the corresponding HttpSession then manually logout the HttpSession. Is this possible?
Now Spring Session supports WebSockets. Follow this guide to add it to your project. Then, in your SessionDisconnectEvent listener, you can get your HttpSessionID this way:
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
public class WebSocketDisconnectHandler<S>
implements ApplicationListener<SessionDisconnectEvent> {
public void onApplicationEvent(SessionDisconnectEvent event) {
String session = SimpMessageHeaderAccessor.getSessionAttributes(event.getMessage().getHeaders()).get("HTTP.SESSION.ID").toString();
}
}
(Other headers values you can access:)
headers {simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={X-XSRF-TOKEN=[cb73273e-bff3-4eb7-965d-4c696e22c25a], accept-version=[1.1,1.0], heart-beat=[10000,10000]}, simpSessionAttributes={HTTP.SESSION.ID=6dd63204-d5ec-4362-8f37-29af5605298d, org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@10b64145, org.springframework.security.web.csrf.CsrfToken=org.springframework.security.web.csrf.DefaultCsrfToken@10b64145}, simpHeartbeat=[J@3955ead4, simpSessionId=3x25c1e5}
Be sure to register this as a bean in a WebSocket config file that extends ExpiringSession:
import your.package.WebSocketDisconnectHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.ExpiringSession;
@Configuration
public class WebSocketHandlersConfig<S extends ExpiringSession> {
@Bean
public WebSocketDisconnectHandler<S> webSocketDisconnectHandler() {
return new WebSocketDisconnectHandler<S>();
}
}
I think you need a interceptor, you will get empty sessionAttributes
without it.
You need to add HttpSessionHandshakeInterceptor
in the dispatcher-servlet.xml
:
<websocket:message-broker
application-destination-prefix="/test">
<websocket:stomp-endpoint path="/sbapp">
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs session-cookie-needed="true" />
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic, /message" />
</websocket:message-broker>
And then you will be able to get session in the controller:
@MessageMapping("/authorization.action")
public Message authorizationAction(
SimpMessageHeaderAccessor headerAccessor, Message message) {
String sessionId = headerAccessor.getSessionId();
Map<String, Object> sessionAttributes = headerAccessor.getSessionAttributes();
System.out.println(sessionId);
System.out.println(sessionAttributes);
// Do something with session
return new Message(...);
}
This worked for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With