Add session attributes to SimpMessageHeaderAccessor
This change exposes the WebSocketSession attributes through a message header.
The StompSubProtocolHandler adds this to incoming messages.
For now messaging handling methods can access the map via @Header, e.g.:
@Header(StompHeaderAccessor.SESSION_ATTRIBUTES) Map<String, Object> attrs) {
Issue: SPR-11566
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,8 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
|
||||
|
||||
public static final String SESSION_ID_HEADER = "simpSessionId";
|
||||
|
||||
public static final String SESSION_ATTRIBUTES = "simpSessionAttributes";
|
||||
|
||||
public static final String SUBSCRIPTION_ID_HEADER = "simpSubscriptionId";
|
||||
|
||||
public static final String USER_HEADER = "simpUser";
|
||||
@@ -127,6 +129,15 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
|
||||
setHeader(SESSION_ID_HEADER, sessionId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getSessionAttributes() {
|
||||
return (Map<String, Object>) getHeader(SESSION_ATTRIBUTES);
|
||||
}
|
||||
|
||||
public void setSessionAttributes(Map<String, Object> attributes) {
|
||||
setHeader(SESSION_ATTRIBUTES, attributes);
|
||||
}
|
||||
|
||||
public Principal getUser() {
|
||||
return (Principal) getHeader(USER_HEADER);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.socket.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -43,16 +44,19 @@ public abstract class AbstractWebSocketSession<T> implements NativeWebSocketSess
|
||||
|
||||
private T nativeSession;
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
private final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance and associate the given attributes with it.
|
||||
*
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket session
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
|
||||
* session; the provided attributes are copied, the original map is not used.
|
||||
*/
|
||||
public AbstractWebSocketSession(Map<String, Object> attributes) {
|
||||
this.attributes = attributes;
|
||||
if (attributes != null) {
|
||||
this.attributes.putAll(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ public class JettyWebSocketSession extends AbstractWebSocketSession<Session> {
|
||||
/**
|
||||
* Create a new {@link JettyWebSocketSession} instance associated with the given user.
|
||||
*
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket session
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
|
||||
* session; the provided attributes are copied, the original map is not used.
|
||||
* @param user the user associated with the session; if {@code null} we'll fallback on the user
|
||||
* available via {@link org.eclipse.jetty.websocket.api.Session#getUpgradeRequest()}
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,8 @@ public class StandardWebSocketSession extends AbstractWebSocketSession<Session>
|
||||
* Class constructor.
|
||||
*
|
||||
* @param headers the headers of the handshake request
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket session
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
|
||||
* session; the provided attributes are copied, the original map is not used.
|
||||
* @param localAddress the address on which the request was received
|
||||
* @param remoteAddress the address of the remote client
|
||||
*/
|
||||
|
||||
@@ -133,6 +133,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler {
|
||||
}
|
||||
|
||||
headers.setSessionId(session.getId());
|
||||
headers.setSessionAttributes(session.getAttributes());
|
||||
headers.setUser(session.getPrincipal());
|
||||
|
||||
message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headers).build();
|
||||
|
||||
@@ -37,17 +37,19 @@ public interface HandshakeHandler {
|
||||
|
||||
/**
|
||||
* Initiate the handshake.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @param wsHandler the handler to process WebSocket messages; see
|
||||
* {@link PerConnectionWebSocketHandler} for providing a handler with
|
||||
* per-connection lifecycle.
|
||||
* @param attributes handshake request specific attributes to be set on the WebSocket
|
||||
* session via {@link HandshakeInterceptor} and thus made available to the
|
||||
* {@link WebSocketHandler};
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
|
||||
* session; the provided attributes are copied, the original map is not used.
|
||||
*
|
||||
* @return whether the handshake negotiation was successful or not. In either case the
|
||||
* response status, headers, and body will have been updated to reflect the
|
||||
* result of the negotiation
|
||||
*
|
||||
* @throws HandshakeFailureException thrown when handshake processing failed to
|
||||
* complete due to an internal, unrecoverable error, i.e. a server error as
|
||||
* opposed to a failure to successfully negotiate the handshake.
|
||||
|
||||
@@ -40,8 +40,8 @@ public interface HandshakeInterceptor {
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @param wsHandler the target WebSocket handler
|
||||
* @param attributes attributes from the HTTP handshake to associate with the
|
||||
* WebSocket session, i.e. via {@link WebSocketSession#getAttributes()}
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
|
||||
* session; the provided attributes are copied, the original map is not used.
|
||||
* @return whether to proceed with the handshake {@code true} or abort {@code false}
|
||||
*/
|
||||
boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
|
||||
|
||||
@@ -110,7 +110,8 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
||||
* @param id the session ID
|
||||
* @param config SockJS service configuration options
|
||||
* @param handler the recipient of SockJS messages
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket session
|
||||
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
|
||||
* session; the provided attributes are copied, the original map is not used.
|
||||
*/
|
||||
public AbstractSockJsSession(String id, SockJsServiceConfig config, WebSocketHandler handler,
|
||||
Map<String, Object> attributes) {
|
||||
|
||||
@@ -170,6 +170,7 @@ public class StompSubProtocolHandlerTests {
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.wrap(actual);
|
||||
assertEquals(StompCommand.CONNECT, headers.getCommand());
|
||||
assertEquals("s1", headers.getSessionId());
|
||||
assertNotNull(headers.getSessionAttributes());
|
||||
assertEquals("joe", headers.getUser().getName());
|
||||
assertEquals("guest", headers.getLogin());
|
||||
assertEquals("PROTECTED", headers.getPasscode());
|
||||
|
||||
Reference in New Issue
Block a user