Spring Security Messaging provides comprehensive security support for Spring's messaging abstractions and WebSocket applications. It enables developers to integrate authentication and authorization into message-based and real-time communication systems with channel interceptors, authorization managers, and reactive support.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
<version>7.0.0</version>
</dependency>Spring Security Messaging requires:
Maven Dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
<version>7.0.0</version>
</dependency>
<!-- For reactive support -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<!-- For WebSocket support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
</dependencies>// Authorization
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor;
import org.springframework.security.messaging.access.intercept.MessageAuthorizationContext;
// Security Context
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
import org.springframework.security.messaging.context.SecurityContextPropagationChannelInterceptor;
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
// CSRF Protection
import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor;
import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
// Message Matching
import org.springframework.security.messaging.access.intercept.MessageMatcher;
import org.springframework.security.messaging.access.intercept.PathPatternMessageMatcher;
import org.springframework.security.messaging.access.intercept.SimpMessageTypeMatcher;
import org.springframework.security.messaging.access.intercept.AndMessageMatcher;
import org.springframework.security.messaging.access.intercept.OrMessageMatcher;
// Expression Handling
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
import org.springframework.security.messaging.access.expression.MessageAuthorizationContextSecurityExpressionHandler;
// Reactive Support
import org.springframework.security.messaging.handler.invocation.reactive.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.messaging.handler.invocation.reactive.CurrentSecurityContextArgumentResolver;import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor;
import org.springframework.security.messaging.context.SecurityContextPropagationChannelInterceptor;
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(ChannelRegistration registration) {
// Propagate security context (required for @AuthenticationPrincipal)
registration.interceptors(new SecurityContextPropagationChannelInterceptor());
// Configure authorization
MessageMatcherDelegatingAuthorizationManager authManager =
MessageMatcherDelegatingAuthorizationManager.builder()
.nullDestMatcher().authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").permitAll()
.simpDestMatchers("/app/**").hasRole("USER")
.simpSubscribeDestMatchers("/topic/**").hasRole("USER")
.anyMessage().denyAll()
.build();
registration.interceptors(new AuthorizationChannelInterceptor(authManager));
}
}import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
@MessageMapping("/chat")
public void processMessage(@AuthenticationPrincipal UserDetails user, String message) {
// user contains the authenticated principal
// Throws IllegalArgumentException if user is null and no anonymous auth configured
String username = user.getUsername();
// Process message...
}
// Handle null principal gracefully
@MessageMapping("/chat-safe")
public void processMessageSafe(
@AuthenticationPrincipal(required = false) UserDetails user,
String message
) {
if (user != null) {
String username = user.getUsername();
// Process authenticated message...
} else {
// Handle anonymous/unauthenticated message...
}
}
}Spring Security Messaging is organized around several key functional areas:
Configure fine-grained access control rules for messages based on destination patterns, message types, and custom criteria. The primary API for securing message channels with role-based and expression-based authorization.
/**
* Authorization manager that delegates based on MessageMatcher patterns.
* Thread-safe for concurrent use.
*
* @since 5.8
*/
public final class MessageMatcherDelegatingAuthorizationManager
implements AuthorizationManager<Message<?>> {
/**
* Creates a new builder for configuring authorization rules.
*
* @return a Builder instance
*/
public static Builder builder();
/**
* Performs authorization check on the message.
*
* @param authentication supplier of authentication to check (must not be null)
* @param message the message to authorize (must not be null)
* @return authorization result (never null)
* @throws IllegalArgumentException if authentication or message is null
*/
public AuthorizationResult authorize(
Supplier<? extends Authentication> authentication,
Message<?> message
);
}Builder API:
public static final class Builder {
/**
* Matches any message. Should typically be last in chain.
*
* @return Constraint for configuring authorization rule
*/
public Constraint anyMessage();
/**
* Matches messages with null destination.
*
* @return Constraint for configuring authorization rule
*/
public Constraint nullDestMatcher();
/**
* Matches messages by STOMP message type.
*
* @param typesToMatch the STOMP message types to match (must not be null or empty)
* @return Constraint for configuring authorization rule
* @throws IllegalArgumentException if typesToMatch is null or empty
*/
public Constraint simpTypeMatchers(SimpMessageType... typesToMatch);
/**
* Matches messages by destination pattern for any message type.
* Uses Ant-style path patterns.
*
* @param patterns destination patterns (must not be null or empty)
* @return Constraint for configuring authorization rule
* @throws IllegalArgumentException if patterns is null or empty
*/
public Constraint simpDestMatchers(String... patterns);
/**
* Matches MESSAGE type messages by destination pattern.
*
* @param patterns destination patterns (must not be null or empty)
* @return Constraint for configuring authorization rule
*/
public Constraint simpMessageDestMatchers(String... patterns);
/**
* Matches SUBSCRIBE type messages by destination pattern.
*
* @param patterns destination patterns (must not be null or empty)
* @return Constraint for configuring authorization rule
*/
public Constraint simpSubscribeDestMatchers(String... patterns);
/**
* Matches using custom message matchers.
*
* @param matchers custom MessageMatcher instances (must not be null or empty)
* @return Constraint for configuring authorization rule
* @throws IllegalArgumentException if matchers is null or empty
*/
public Constraint matchers(MessageMatcher<?>... matchers);
/**
* Builds the MessageMatcherDelegatingAuthorizationManager.
*
* @return configured authorization manager (never null)
* @throws IllegalStateException if no rules are configured
*/
public MessageMatcherDelegatingAuthorizationManager build();
}Constraint API:
public interface Constraint {
/**
* Requires user to have the specified role (ROLE_ prefix added automatically).
*
* @param role the role name without ROLE_ prefix (must not be null or empty)
* @return Builder for configuring additional rules
* @throws IllegalArgumentException if role is null or empty
*/
Builder hasRole(String role);
/**
* Requires user to have any of the specified roles.
*
* @param roles role names without ROLE_ prefix (must not be null or empty)
* @return Builder for configuring additional rules
*/
Builder hasAnyRole(String... roles);
/**
* Requires user to have the specified authority.
*
* @param authority the authority name (must not be null or empty)
* @return Builder for configuring additional rules
*/
Builder hasAuthority(String authority);
/**
* Requires user to have any of the specified authorities.
*
* @param authorities authority names (must not be null or empty)
* @return Builder for configuring additional rules
*/
Builder hasAnyAuthority(String... authorities);
/**
* Permits all users (authenticated and anonymous).
*
* @return Builder for configuring additional rules
*/
Builder permitAll();
/**
* Denies all users.
*
* @return Builder for configuring additional rules
*/
Builder denyAll();
/**
* Requires user to be authenticated (including remember-me).
*
* @return Builder for configuring additional rules
*/
Builder authenticated();
/**
* Requires full authentication (not remember-me).
*
* @return Builder for configuring additional rules
*/
Builder fullyAuthenticated();
/**
* Requires remember-me authentication.
*
* @return Builder for configuring additional rules
*/
Builder rememberMe();
/**
* Requires anonymous authentication.
*
* @return Builder for configuring additional rules
*/
Builder anonymous();
/**
* Uses custom AuthorizationManager for authorization decision.
*
* @param manager custom authorization manager (must not be null)
* @return Builder for configuring additional rules
* @throws IllegalArgumentException if manager is null
*/
Builder access(AuthorizationManager<MessageAuthorizationContext<?>> manager);
}Manage authentication context across message processing threads. Choose between classic header-based propagation or modern context-capturing approach.
/**
* Classic approach: obtains Authentication from message headers.
* Thread-safe when used with proper SecurityContextHolderStrategy.
*
* @since 4.0
*/
public final class SecurityContextChannelInterceptor
implements ExecutorChannelInterceptor, ChannelInterceptor {
/**
* Default header name: "simpUser"
*/
public static final String USER_HEADER = "simpUser";
/**
* Creates interceptor using default USER_HEADER.
*/
public SecurityContextChannelInterceptor();
/**
* Creates interceptor with custom header name.
*
* @param authenticationHeaderName name of header containing authentication (must not be null)
* @throws IllegalArgumentException if authenticationHeaderName is null
*/
public SecurityContextChannelInterceptor(String authenticationHeaderName);
/**
* Sets anonymous authentication to use when no authentication is present.
*
* @param authentication the anonymous authentication (can be null)
*/
public void setAnonymousAuthentication(Authentication authentication);
/**
* Sets the SecurityContextHolderStrategy for managing security context.
*
* @param strategy the strategy to use (must not be null)
* @throws IllegalArgumentException if strategy is null
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy);
/**
* Intercepts message before sending and sets up security context.
*
* @param message the message being sent (must not be null)
* @param channel the channel (must not be null)
* @return the message (never null)
* @throws IllegalArgumentException if message or channel is null
*/
public Message<?> preSend(Message<?> message, MessageChannel channel);
/**
* Cleans up security context after message send completes.
*
* @param message the message (must not be null)
* @param channel the channel (must not be null)
* @param sent whether send succeeded
* @param ex exception if send failed (can be null)
*/
public void afterSendCompletion(
Message<?> message,
MessageChannel channel,
boolean sent,
Exception ex
);
}/**
* Modern approach (since 6.2): captures Authentication from current SecurityContext.
* Cannot be used together with SecurityContextChannelInterceptor.
* Thread-safe when used with proper SecurityContextHolderStrategy.
*
* @since 6.2
*/
public final class SecurityContextPropagationChannelInterceptor
implements ExecutorChannelInterceptor {
/**
* Default header name: "simpUser"
*/
public static final String USER_HEADER = "simpUser";
/**
* Creates interceptor using default USER_HEADER.
*/
public SecurityContextPropagationChannelInterceptor();
/**
* Creates interceptor with custom header name.
*
* @param authenticationHeaderName name of header to store authentication (must not be null)
* @throws IllegalArgumentException if authenticationHeaderName is null
*/
public SecurityContextPropagationChannelInterceptor(String authenticationHeaderName);
/**
* Sets the SecurityContextHolderStrategy for managing security context.
*
* @param strategy the strategy to use (must not be null)
* @throws IllegalArgumentException if strategy is null
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy);
/**
* Sets anonymous authentication to use when no authentication is present.
*
* @param authentication the anonymous authentication (can be null)
*/
public void setAnonymousAuthentication(Authentication authentication);
/**
* Captures current authentication and stores in message header.
*
* @param message the message (must not be null)
* @param channel the channel (must not be null)
* @return message with authentication in header (never null)
* @throws IllegalArgumentException if message or channel is null
*/
public Message<?> preSend(Message<?> message, MessageChannel channel);
}Protect WebSocket connections from Cross-Site Request Forgery attacks using token validation during handshake and message processing.
/**
* HandshakeInterceptor that loads CsrfToken from HTTP request during
* WebSocket handshake and stores in WebSocket session attributes.
* Thread-safe.
*
* @since 4.0
*/
public final class CsrfTokenHandshakeInterceptor implements HandshakeInterceptor {
/**
* Loads CSRF token from request and stores in WebSocket attributes.
*
* @param request the HTTP request (must not be null)
* @param response the HTTP response (must not be null)
* @param wsHandler the WebSocket handler (must not be null)
* @param attributes WebSocket session attributes (mutable, must not be null)
* @return true to proceed with handshake, false to reject
* @throws IllegalArgumentException if any parameter is null
*/
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes
);
/**
* Called after handshake completion (no-op implementation).
*
* @param request the HTTP request (must not be null)
* @param response the HTTP response (must not be null)
* @param wsHandler the WebSocket handler (must not be null)
* @param exception exception if handshake failed (can be null)
*/
public void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception
);
}/**
* ChannelInterceptor that validates CSRF token in CONNECT messages.
* Expects token to be present in message headers (loaded by handshake interceptor).
* Thread-safe.
*
* @since 4.0
*/
public final class CsrfChannelInterceptor implements ChannelInterceptor {
/**
* Intercepts message before sending and validates CSRF token for CONNECT messages.
*
* @param message the message (must not be null)
* @param channel the channel (must not be null)
* @return the message if valid (never null)
* @throws InvalidCsrfTokenException if CSRF token is invalid or missing for CONNECT messages
* @throws IllegalArgumentException if message or channel is null
*/
public Message<?> preSend(Message<?> message, MessageChannel channel);
}/**
* ChannelInterceptor that validates XOR-masked CSRF tokens in CONNECT messages.
* Use with XorCsrfTokenRequestAttributeHandler for enhanced CSRF protection.
* Thread-safe.
*
* @since 5.8
*/
public final class XorCsrfChannelInterceptor implements ChannelInterceptor {
/**
* Intercepts message and validates XOR-masked CSRF token for CONNECT messages.
*
* @param message the message (must not be null)
* @param channel the channel (must not be null)
* @return the message if valid (never null)
* @throws InvalidCsrfTokenException if CSRF token is invalid or missing for CONNECT messages
* @throws IllegalArgumentException if message or channel is null
*/
public Message<?> preSend(Message<?> message, MessageChannel channel);
}Match messages based on destination patterns, message types, or custom criteria. Supports path variables and composite matching logic.
/**
* Strategy interface for matching messages.
* Thread-safe implementations are recommended.
*
* @param <T> the message payload type
* @since 4.0
*/
public interface MessageMatcher<T> {
/**
* Returns true if this matcher matches the given message.
*
* @param message the message to match (must not be null)
* @return true if message matches
* @throws IllegalArgumentException if message is null
*/
boolean matches(Message<? extends T> message);
/**
* Returns match result with extracted path variables.
*
* @param message the message to match (must not be null)
* @return match result including extracted variables (never null)
* @since 6.5
*/
default MatchResult matcher(Message<? extends T> message) {
return matches(message) ? MatchResult.match() : MatchResult.notMatch();
}
/**
* Matcher that matches every message.
*/
MessageMatcher<Object> ANY_MESSAGE = (message) -> true;
}/**
* MessageMatcher that matches based on destination path patterns.
* Supports path variables like /app/user/{userId}/*.
* Thread-safe.
*
* @since 6.5
*/
public final class PathPatternMessageMatcher implements MessageMatcher<Object> {
/**
* Matcher for messages with null destination.
*/
public static final MessageMatcher<Object> NULL_DESTINATION_MATCHER;
/**
* Creates builder with default PathPatternParser.
*
* @return builder instance (never null)
*/
public static Builder withDefaults();
/**
* Creates builder with custom PathPatternParser.
*
* @param parser the path pattern parser to use (must not be null)
* @return builder instance (never null)
* @throws IllegalArgumentException if parser is null
*/
public static Builder withPathPatternParser(PathPatternParser parser);
/**
* Returns true if message destination matches the pattern.
*
* @param message the message to match (must not be null)
* @return true if destination matches pattern
* @throws IllegalArgumentException if message is null
*/
public boolean matches(Message<?> message);
/**
* Returns match result with extracted path variables.
*
* @param message the message to match (must not be null)
* @return match result with variables (never null)
* @throws IllegalArgumentException if message is null
*/
public MatchResult matcher(Message<?> message);
}/**
* MessageMatcher that matches based on STOMP message type.
* Thread-safe.
*
* @since 4.0
*/
public class SimpMessageTypeMatcher implements MessageMatcher<Object> {
/**
* Creates matcher for the specified message type.
*
* @param typeToMatch the STOMP message type to match (must not be null)
* @throws IllegalArgumentException if typeToMatch is null
*/
public SimpMessageTypeMatcher(SimpMessageType typeToMatch);
/**
* Returns true if message has the matching type.
*
* @param message the message to match (must not be null)
* @return true if message type matches
* @throws IllegalArgumentException if message is null
*/
public boolean matches(Message<?> message);
}Inject authenticated user principals directly into message handler method parameters using the @AuthenticationPrincipal annotation.
/**
* HandlerMethodArgumentResolver that resolves parameters annotated
* with @AuthenticationPrincipal to inject the authenticated principal.
* Thread-safe.
*
* @since 4.0
*/
public final class AuthenticationPrincipalArgumentResolver
implements HandlerMethodArgumentResolver {
/**
* Checks if this resolver supports the given parameter.
*
* @param parameter the method parameter (must not be null)
* @return true if parameter is annotated with @AuthenticationPrincipal
* @throws IllegalArgumentException if parameter is null
*/
public boolean supportsParameter(MethodParameter parameter);
/**
* Resolves the authenticated principal from SecurityContext.
*
* @param parameter the method parameter (must not be null)
* @param message the current message (must not be null)
* @return the authenticated principal (can be null if required=false)
* @throws IllegalArgumentException if principal is required but not found
* @throws IllegalArgumentException if parameter or message is null
*/
public Object resolveArgument(MethodParameter parameter, Message<?> message);
/**
* Sets the SecurityContextHolderStrategy for obtaining authentication.
*
* @param securityContextHolderStrategy the strategy to use (must not be null)
* @throws IllegalArgumentException if strategy is null
* @since 5.8
*/
public void setSecurityContextHolderStrategy(
SecurityContextHolderStrategy securityContextHolderStrategy
);
/**
* Sets template defaults for annotation expression evaluation.
*
* @param templateDefaults the template defaults (can be null)
* @since 6.4
*/
public void setTemplateDefaults(
AnnotationTemplateExpressionDefaults templateDefaults
);
}Support for reactive messaging applications using Project Reactor, providing reactive argument resolvers for @AuthenticationPrincipal and @CurrentSecurityContext.
/**
* Reactive HandlerMethodArgumentResolver for @AuthenticationPrincipal parameters.
* Returns Mono<Object> to support reactive message handling.
* Thread-safe.
*
* @since 5.2
*/
// In package: org.springframework.security.messaging.handler.invocation.reactive
public class AuthenticationPrincipalArgumentResolver
implements HandlerMethodArgumentResolver {
/**
* Sets the BeanResolver for resolving beans in SpEL expressions.
*
* @param beanResolver the bean resolver (can be null)
*/
public void setBeanResolver(BeanResolver beanResolver);
/**
* Sets the ReactiveAdapterRegistry for reactive type conversions.
*
* @param adapterRegistry the adapter registry (must not be null)
* @throws IllegalArgumentException if adapterRegistry is null
*/
public void setAdapterRegistry(ReactiveAdapterRegistry adapterRegistry);
/**
* Checks if this resolver supports the given parameter.
*
* @param parameter the method parameter (must not be null)
* @return true if parameter is annotated with @AuthenticationPrincipal
* @throws IllegalArgumentException if parameter is null
*/
public boolean supportsParameter(MethodParameter parameter);
/**
* Resolves the authenticated principal reactively from ReactiveSecurityContextHolder.
*
* @param parameter the method parameter (must not be null)
* @param message the current message (must not be null)
* @return Mono containing the authenticated principal (never null, may emit null)
* @throws IllegalArgumentException if parameter or message is null
*/
public Mono<Object> resolveArgument(MethodParameter parameter, Message<?> message);
/**
* Sets template defaults for annotation expression evaluation.
*
* @param templateDefaults the template defaults (can be null)
* @since 6.4
*/
public void setTemplateDefaults(
AnnotationTemplateExpressionDefaults templateDefaults
);
}/**
* Reactive HandlerMethodArgumentResolver for @CurrentSecurityContext parameters.
* Returns Mono<SecurityContext> to support reactive message handling.
* Thread-safe.
*
* @since 5.2
*/
// In package: org.springframework.security.messaging.handler.invocation.reactive
public class CurrentSecurityContextArgumentResolver
implements HandlerMethodArgumentResolver {
/**
* Sets the BeanResolver for resolving beans in SpEL expressions.
*
* @param beanResolver the bean resolver (can be null)
*/
public void setBeanResolver(BeanResolver beanResolver);
/**
* Sets the ReactiveAdapterRegistry for reactive type conversions.
*
* @param adapterRegistry the adapter registry (must not be null)
* @throws IllegalArgumentException if adapterRegistry is null
*/
public void setAdapterRegistry(ReactiveAdapterRegistry adapterRegistry);
/**
* Checks if this resolver supports the given parameter.
*
* @param parameter the method parameter (must not be null)
* @return true if parameter is supported
* @throws IllegalArgumentException if parameter is null
*/
public boolean supportsParameter(MethodParameter parameter);
/**
* Resolves the SecurityContext reactively from ReactiveSecurityContextHolder.
*
* @param parameter the method parameter (must not be null)
* @param message the current message (must not be null)
* @return Mono containing the SecurityContext (never null, may emit null)
* @throws IllegalArgumentException if parameter or message is null
*/
public Mono<Object> resolveArgument(MethodParameter parameter, Message<?> message);
/**
* Sets template defaults for annotation expression evaluation.
*
* @param templateDefaults the template defaults (can be null)
* @since 6.4
*/
public void setTemplateDefaults(
AnnotationTemplateExpressionDefaults templateDefaults
);
}Use Spring Expression Language (SpEL) for complex authorization rules with custom security expressions and evaluation contexts.
/**
* Default SecurityExpressionHandler for Message-based security expressions.
* Creates evaluation contexts with MessageSecurityExpressionRoot.
* Thread-safe.
*
* @param <T> the message payload type
* @since 4.0
*/
public class DefaultMessageSecurityExpressionHandler<T>
extends AbstractSecurityExpressionHandler<Message<T>> {
/**
* Creates evaluation context for the given authentication and message.
*
* @param authentication supplier of authentication to evaluate (must not be null)
* @param message the message being evaluated (must not be null)
* @return evaluation context for SpEL expressions (never null)
* @throws IllegalArgumentException if authentication or message is null
*/
public EvaluationContext createEvaluationContext(
Supplier<? extends Authentication> authentication,
Message<T> message
);
}/**
* SecurityExpressionHandler for MessageAuthorizationContext that supports
* path variables extracted from destination patterns.
* Thread-safe.
*
* @since 5.8
*/
public final class MessageAuthorizationContextSecurityExpressionHandler
implements SecurityExpressionHandler<MessageAuthorizationContext<?>> {
/**
* Creates handler with default DefaultMessageSecurityExpressionHandler.
*/
public MessageAuthorizationContextSecurityExpressionHandler();
/**
* Creates handler wrapping the specified delegate.
*
* @param expressionHandler delegate handler for Message expressions (must not be null)
* @throws IllegalArgumentException if expressionHandler is null
*/
public MessageAuthorizationContextSecurityExpressionHandler(
SecurityExpressionHandler<Message<?>> expressionHandler
);
/**
* Returns the expression parser used for parsing SpEL expressions.
*
* @return the expression parser (never null)
*/
public ExpressionParser getExpressionParser();
/**
* Creates evaluation context for the given authentication and context.
*
* @param authentication the authentication to evaluate (must not be null)
* @param context the message authorization context (must not be null)
* @return evaluation context for SpEL expressions (never null)
* @throws IllegalArgumentException if authentication or context is null
*/
public EvaluationContext createEvaluationContext(
Authentication authentication,
MessageAuthorizationContext<?> context
);
/**
* Creates evaluation context with authentication supplier.
*
* @param authentication supplier of authentication to evaluate (must not be null)
* @param context the message authorization context (must not be null)
* @return evaluation context for SpEL expressions (never null)
* @throws IllegalArgumentException if authentication or context is null
*/
public EvaluationContext createEvaluationContext(
Supplier<? extends Authentication> authentication,
MessageAuthorizationContext<?> context
);
}Context object holding a message and extracted path variables for authorization decisions.
/**
* Holds a Message and extracted path variables for authorization.
* Immutable and thread-safe.
*
* @param <T> the message payload type
* @since 5.8
*/
public final class MessageAuthorizationContext<T> {
/**
* Creates context with message only.
*
* @param message the message (must not be null)
* @throws IllegalArgumentException if message is null
*/
public MessageAuthorizationContext(Message<T> message);
/**
* Creates context with message and path variables.
*
* @param message the message (must not be null)
* @param variables path variables extracted from destination (can be null, treated as empty)
* @throws IllegalArgumentException if message is null
*/
public MessageAuthorizationContext(Message<T> message, Map<String, String> variables);
/**
* Returns the message.
*
* @return the message (never null)
*/
public Message<T> getMessage();
/**
* Returns extracted path variables from destination pattern matching.
*
* @return map of variable names to values (never null, may be empty)
*/
public Map<String, String> getVariables();
}Channel interceptor that performs authorization checks on messages before they are sent.
/**
* ChannelInterceptor that performs authorization on messages before they are sent.
* Thread-safe.
*
* @since 5.8
*/
public final class AuthorizationChannelInterceptor implements ChannelInterceptor {
/**
* Creates interceptor with the specified authorization manager.
*
* @param preSendAuthorizationManager authorization manager for pre-send checks (must not be null)
* @throws IllegalArgumentException if preSendAuthorizationManager is null
*/
public AuthorizationChannelInterceptor(
AuthorizationManager<Message<?>> preSendAuthorizationManager
);
/**
* Intercepts message before sending and performs authorization check.
*
* @param message the message to authorize (must not be null)
* @param channel the channel (must not be null)
* @return the message if authorized (never null)
* @throws AccessDeniedException if authorization fails
* @throws IllegalArgumentException if message or channel is null
*/
public Message<?> preSend(Message<?> message, MessageChannel channel);
/**
* Sets the SecurityContextHolderStrategy for obtaining authentication.
*
* @param securityContextHolderStrategy the strategy to use (must not be null)
* @throws IllegalArgumentException if strategy is null
*/
public void setSecurityContextHolderStrategy(
SecurityContextHolderStrategy securityContextHolderStrategy
);
/**
* Sets the publisher for authorization events.
*
* @param eventPublisher the event publisher (can be null)
*/
public void setAuthorizationEventPublisher(
AuthorizationEventPublisher eventPublisher
);
}Result of a message matching operation, including match status and extracted path variables.
/**
* Result of a message matching operation.
* Immutable and thread-safe.
*
* @since 6.5
*/
public interface MatchResult {
/**
* Returns whether the message matched.
*
* @return true if matched
*/
boolean isMatch();
/**
* Returns extracted path variables from pattern matching.
*
* @return map of variable names to values (never null, may be empty)
*/
Map<String, String> getVariables();
/**
* Creates a match result with no variables.
*
* @return match result (never null)
*/
static MatchResult match();
/**
* Creates a match result with extracted variables.
*
* @param variables the extracted path variables (can be null, treated as empty)
* @return match result (never null)
*/
static MatchResult match(Map<String, String> variables);
/**
* Creates a non-match result.
*
* @return non-match result (never null)
*/
static MatchResult notMatch();
}@Controller
public class SecureMessageController {
@MessageMapping("/secure")
public void handleSecureMessage(
@AuthenticationPrincipal UserDetails user,
String message
) {
try {
// Process message...
} catch (AccessDeniedException e) {
// Handle authorization failure
logger.error("Access denied for user: {}", user.getUsername(), e);
} catch (IllegalArgumentException e) {
// Handle invalid input
logger.error("Invalid message format", e);
}
}
}All components in Spring Security Messaging are designed to be thread-safe:
Important: When using custom SecurityContextHolderStrategy, ensure it's thread-safe for your use case.
For high-throughput scenarios, consider:
Cause: Security context not propagated to message handling thread.
Solution: Ensure SecurityContextPropagationChannelInterceptor or SecurityContextChannelInterceptor is registered:
@Override
protected void configureInbound(ChannelRegistration registration) {
registration.interceptors(new SecurityContextPropagationChannelInterceptor());
}Cause: No matching rule or rules evaluated in wrong order.
Solution: Ensure rules are ordered from most specific to least specific, and include .anyMessage().denyAll() as final rule if needed.
Cause: Token not included in CONNECT frame headers or token handler mismatch.
Solution: Ensure CsrfTokenHandshakeInterceptor is registered and client includes token in CONNECT headers. Match interceptor type (CsrfChannelInterceptor vs XorCsrfChannelInterceptor) with token handler.