Reputation: 423
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?
Upvotes: 6
Views: 18325
Reputation: 91
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>();
}
}
Upvotes: 5
Reputation: 3656
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.
Upvotes: 4
Reputation: 485
Take a look at the below post. https://spring.io/blog/2014/09/16/preview-spring-security-websocket-support-sessions
Upvotes: 0