or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

authorization.mdcsrf-protection.mdexpression-handling.mdindex.mdmessage-matching.mdreactive-support.mdsecurity-context.md
tile.json

tessl/maven-spring-security-messaging

Spring Security support for messaging and WebSocket applications

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.springframework.security/spring-security-messaging@7.0.x

To install, run

npx @tessl/cli install tessl/maven-spring-security-messaging@7.0.0

index.mddocs/

Spring Security Messaging

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.

Package Information

  • Package Name: spring-security-messaging
  • Group ID: org.springframework.security
  • Artifact ID: spring-security-messaging
  • Package Type: maven
  • Language: Java
  • Version: 7.0.0
  • Installation:
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-messaging</artifactId>
        <version>7.0.0</version>
    </dependency>

Dependencies

Spring Security Messaging requires:

  • Spring Framework 6.0+
  • Spring Security Core 7.0+
  • Spring Messaging (included in Spring Framework)
  • For reactive support: Project Reactor (reactor-core)

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>

Core Imports

// 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;

Quick Start

Minimal WebSocket Security Configuration

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));
    }
}

Accessing Authenticated User in Message Handlers

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...
        }
    }
}

Architecture

Spring Security Messaging is organized around several key functional areas:

  • Authorization System: Message-based access control using pattern matching and authorization managers
  • Security Context Management: Propagation of authentication across message handling threads
  • CSRF Protection: Token-based CSRF validation for WebSocket connections
  • Message Matching: Flexible pattern matching for destinations, message types, and custom criteria
  • Reactive Support: Reactive argument resolvers for Project Reactor-based messaging
  • Expression Evaluation: SpEL-based security expressions for complex authorization rules

Capabilities

Message Authorization

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);
}

Message Authorization

Security Context Propagation

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);
}

Security Context

CSRF Protection

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);
}

CSRF Protection

Message Matching

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);
}

Message Matching

Authentication Principal Resolution

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
    );
}

Security Context

Reactive Support

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
    );
}

Reactive Support

Expression-Based Authorization

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
    );
}

Expression Handling

Types

MessageAuthorizationContext

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();
}

AuthorizationChannelInterceptor

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
    );
}

MatchResult

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();
}

Error Handling

Common Exceptions

  • AccessDeniedException: Thrown when authorization fails
  • InvalidCsrfTokenException: Thrown when CSRF token validation fails
  • IllegalArgumentException: Thrown when null parameters are provided
  • IllegalStateException: Thrown when configuration is invalid

Error Handling Example

@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);
        }
    }
}

Thread Safety

All components in Spring Security Messaging are designed to be thread-safe:

  • MessageMatcherDelegatingAuthorizationManager: Thread-safe for concurrent authorization checks
  • SecurityContextChannelInterceptor: Thread-safe when used with proper SecurityContextHolderStrategy
  • SecurityContextPropagationChannelInterceptor: Thread-safe when used with proper SecurityContextHolderStrategy
  • CsrfChannelInterceptor: Thread-safe
  • AuthorizationChannelInterceptor: Thread-safe
  • MessageMatcher implementations: Should be thread-safe

Important: When using custom SecurityContextHolderStrategy, ensure it's thread-safe for your use case.

Performance Considerations

  • Authorization checks: Typically < 1ms overhead per message
  • Security context propagation: Minimal overhead (~0.1ms)
  • CSRF validation: ~0.2ms overhead for CONNECT messages only
  • Expression evaluation: Varies with expression complexity (typically 0.5-2ms)

For high-throughput scenarios, consider:

  • Caching authorization decisions when appropriate
  • Using simple role checks instead of complex expressions
  • Minimizing path variable extraction for frequently matched patterns

Troubleshooting

Issue: @AuthenticationPrincipal returns null

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());
}

Issue: Authorization always denies

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.

Issue: CSRF token validation fails

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.