Spring Webflux Websocket Security - Basic Authentication
Last Updated :
27 Mar, 2024
Spring WebFlux WebSockets, the authentication data that was included in the HTTP request at the time the WebSocket connection was established is reused. This indicates that WebSockets will receive the Principal on the HttpServletRequest. The Principal on the HttpServletRequest is automatically overridden if we are using Spring Security. More specifically, we just need to make sure to set up Spring Security to authenticate our HTTP-based web application in order to verify that a user has authenticated to our WebSocket application.
In this article, we will learn how to implement basic authentication in Spring Webflux Websocket Security.
Spring Webflux Websocket Security - Basic Authentication
Below is the Example of Spring Webflux Websocket Security - Basic Authentication:
Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.PathMatchers;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.MatchResultMatchers;
@Configuration
@EnableWebFluxSecurity
public class WebSocketSecurityConfig {
// Configure basic authentication with in-memory user details
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new MapReactiveUserDetailsService(user);
}
// Configure security for WebSocket endpoints
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.matchers(ServerWebExchangeMatchers.pathMatchers("/ws/**"))
.authenticated()
.and()
.httpBasic(Customizer.withDefaults());
return http.build();
}
}
Step-by-Step Implementation of Spring Webflux Websocket Security - Basic Authentication
Below are the steps to implement Spring Webflux Websocket Security.
Step 1: Add Maven Dependencies
Now let's outline the general Spring Framework and Spring Security versions we will be utilizing:
<properties>
<spring.version>6.1.2</spring.version>
<spring-security.version>6.1.7</spring-security.version>
<spring-security-messaging.version>6.0.2</spring-security-messaging.version>
</properties>
Step 2: Authorization of WebSocket
We only need to publish an AuthorizationManager<Message<?>> and add the @EnableWebSocketSecurity annotation in order to configure authorization using Java Configuration. bean or the use-authorization-manager attribute in XML.
Java
@Configuration
@EnableWebSocketSecurity
public class WebSocketSecurityConfig {
// This method creates a bean of type AuthorizationManager<Message<?>>.
// The AuthorizationManager is responsible for handling message-level authorization.
// It takes a MessageMatcherDelegatingAuthorizationManager.Builder as a parameter.
@Bean
AuthorizationManager<Message<?>> messageAuthorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
// The following code configures message-level authorization rules.
messages
// Specify that messages with destination "/user/**" should have the "USER" role.
.simpDestMatchers("/user/**").hasRole("USER");
// Return the built MessageMatcherDelegatingAuthorizationManager.
return messages.build();
}
}
Step 3: Use the SpringSecurityMessaging Library
Using the spring-security-messaging framework, WebSocket-specific security is centered on the AbstractSecurityWebSocketMessageBrokerConfigurer class, and our project implements it like below:
Java
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
import org.springframework.security.config.annotation.web.socket.MessageSecurityMetadataSourceRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
/**
* Configure message broker options.
*/
@Override
protected void configureMessageBroker(MessageBrokerRegistry registry) {
// Enable a simple memory-based message broker to send messages to and receive messages from clients
registry.enableSimpleBroker("/secured");
// Set the prefix for destinations that the application is going to use
registry.setApplicationDestinationPrefixes("/app");
}
/**
* Configure security options for the WebSocket.
*/
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
// Allow all messages to and from the "/app" destination (application-level)
messages.simpDestMatchers("/app/**").permitAll();
// Allow messages from all authenticated users to the "/secured/**" destination
messages.simpDestMatchers("/secured/**").authenticated();
}
/**
* Register STOMP endpoints for WebSocket communication.
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// Allow WebSocket connections on the "/socket" endpoint with SockJS fallback
registry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS();
}
}
Step 4: Set up Socket Views and Controllers
To start, let's configure our controllers and socket views for the essential Spring Security coverage:
Java
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
@ComponentScan("com.baeldung.springsecuredsockets")
public class SecurityConfig {
/**
* Configure the security filter chain.
* Order of precedence is crucial; matching occurs from top to bottom.
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry
// Permit access to these URLs without authentication
.requestMatchers("/", "/index", "/authenticate").permitAll()
// URLs under "/secured/" require authentication
.requestMatchers("/secured/**/**", "/secured/**/**/**", "/secured/socket", "/secured/success").authenticated()
// Any other requests require authentication
.anyRequest().authenticated())
// Configure form login settings
.formLogin(httpSecurityFormLoginConfigurer ->
httpSecurityFormLoginConfigurer
.loginPage("/login").permitAll() // Custom login page
.usernameParameter("username") // Username parameter in the login form
.passwordParameter("password") // Password parameter in the login form
.loginProcessingUrl("/authenticate") // URL where the login form is submitted
.successHandler(loginSuccessHandler()) // Custom success handler
.failureUrl("/denied").permitAll()) // URL to redirect on login failure
// Additional configurations can be added here, such as logout settings, CSRF protection, etc.
// ...
return http.build();
}
// You can define a custom login success handler bean if needed
@Bean
public AuthenticationSuccessHandler loginSuccessHandler() {
return new CustomAuthenticationSuccessHandler();
}
// Other beans and configurations can be added as needed
}
Step 5: Provide Security Coverage
Now let's construct an example socket controller and endpoint for which the security coverage was previously given:
Java
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import java.text.SimpleDateFormat;
import java.util.Date;
@Controller
public class SocketController {
// Handle incoming messages from the "/secured/chat" destination
@MessageMapping("/secured/chat")
// Send the processed message to the "/secured/history" destination
@SendTo("/secured/history")
public OutputMessage send(Message msg) throws Exception {
// Create a new OutputMessage with the sender, message text, and timestamp
return new OutputMessage(
msg.getFrom(),
msg.getText(),
new SimpleDateFormat("HH:mm").format(new Date()));
}
}
Step 6: Create SecurityFilterChain bean
Permitting iframes to utilize SockJS transports might be advantageous in some scenarios. We may construct a SecurityFilterChain bean to do this:
Java
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// Disable CSRF protection
http.csrf(AbstractHttpConfigurer::disable)
// Configure other security options as needed
// ...
// Configure security headers, disabling frame options
.headers(httpSecurityHeadersConfigurer ->
httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)
)
// Configure authorization for HTTP requests using default settings
.authorizeHttpRequests(Customizer.withDefaults());
// Build and return the SecurityFilterChain
return http.build();
}
}
- This uses Java-based settings to build up a SecurityFilterChain bean. It sets up default permission for HTTP requests.
- By default, SockJS is set up to prevent transfers via HTML iframe elements. This is done to lessen the possibility of clickjacking.
- Disables CSRF protection, and configures security headers (disabling frame options). Be careful to modify the setup in accordance with your unique security needs.
Similar Reads
Spring Security - Basic Authentication
Spring Security is a framework that allows a programmer to use JEE (Java Enterprise Edition) components to set security limitations on Spring Framework-based web applications. As a core part of the Spring ecosystem, itâs a library that can be utilized and customized to suit the demands of the progra
7 min read
Spring Security - Two Factor Authentication
Two-factor authentication (2FA) is a security method that requires users to provide two forms of authentication to access their accounts. These forms of authentication typically include something the user knows (such as a password or PIN) and something the user has (such as a mobile device or hardwa
10 min read
Spring Security - JDBC Authentication
JDBC or Java Database Connectivity is a Java API to connect and execute the query with the database. It is a specification from Sun Microsystems that provides a standard abstraction(API or Protocol) for Java applications to communicate with various databases. It provides the language with Java datab
8 min read
Spring Security with LDAP Authentication
LDAP (Lightweight Directory Access Protocol) is widely used for identity and access management. It organizes data in a hierarchical structure, optimized for read-heavy operations. LDAP is advantageous due to its scalability and interoperability. In this article, we will create a simple authenticatio
7 min read
Spring Security - Role Based Authentication
Authentication is when anyone wants to access your Rest API they need some Authorization like a Username, Password, and token kind of. So Spring Boot Security has a Spring Boot 6.2.0 version. In the lower version Some Methods are deprecated in spring Security that's why a new thing comes into the pi
4 min read
Spring Security - Form-Based Authentication
Form-Based Authentication in Spring Security provides a secure way to authenticate users using a custom login form instead of the default security prompt. It allows better control over authentication flow, user experience, and security configurations. Key Features: Customizable login and logout mech
5 min read
Reactive JWT Authentication Using Spring WebFlux
JSON Web Token (JWT) authentication is a popular method for securing APIs in microservices architectures. With Spring WebFlux, the reactive web framework, we can create highly scalable and responsive applications. In this article, we will guide you on how to implement JWT authentication in a reactiv
8 min read
Securing Spring Cloud Config Server with Basic Authentication
Spring Cloud Config Server provides externalization for distributed systems. With the increasing importance of microservices, centrally managing configurations becomes crucial. Securing this configuration server is equally important to prevent unauthorized access. Basic authentication is a simple an
4 min read
Security with Spring Security and Spring Webflux
Spring WebFlux is a part of the Spring Framework that supports reactive programming, enabling non-blocking asynchronous request handling. When developing web applications with Spring WebFlux, securing the application is a crucial aspect to ensure unauthorized access is prevented. This article provid
3 min read
Spring Security Custom AuthenticationFailureHandler
In Java, Spring Security is a very powerful framework that can provide comprehensive security services for Java enterprise software applications. One of the essential aspects of the security is authentication and it can be users are verified before granting access to the resource. Spring Security ca
6 min read