添加AbstractSecurityWebSocketMessageBrokerConfigurer实现后应用无法启动求助
Alright, let's figure out why your app won't start when adding the AbstractSecurityWebSocketMessageBrokerConfigurer implementation. From the snippet of your WebSecurityConfig you shared, the issue almost certainly comes from conflicting security configurations or missing setup to integrate HTTP security with WebSocket security properly. Here's how to fix it step by step:
1. Fix the WebSocket Security Configuration
First, make sure your WebSocket security config class is properly annotated and focused on message-level security (not overlapping with your HTTP security rules). Here's a correct implementation:
@Configuration public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { @Override protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { // Define permissions for WebSocket topics/subscriptions messages // Restrict admin-only topics to users with ADMIN role .simpDestMatchers("/admin/**").hasRole("ADMIN") // Allow authenticated users access to user-specific topics .simpDestMatchers("/user/**").hasRole("USER") // Require authentication for all other WebSocket messages .anyMessage().authenticated(); } // Disable same-origin check only if you need cross-origin WebSocket connections // (Leave this as false for production unless absolutely necessary) @Override protected boolean sameOriginDisabled() { return false; } }
2. Adjust Your HTTP Security Config to Allow WebSocket Handshakes
Your existing WebSecurityConfig might be blocking the WebSocket handshake endpoint, which causes startup failures or connection issues. Update it to permit access to your WebSocket endpoints (adjust the paths to match your actual setup, e.g., /ws, /stomp, etc.):
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private static final String SECURE_ADMIN_PASSWORD = "rockandroll"; @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .formLogin() .loginPage("/index.html") .loginProcessingUrl("/login") .defaultSuccessUrl("/dashboard.html", true) // Complete your default success URL here .permitAll() .and() .authorizeRequests() .antMatchers("/css/**", "/js/**", "/index.html").permitAll() // Permit access to WebSocket handshake endpoints .antMatchers("/ws/**", "/stomp/**").permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated(); } // Configure in-memory users (adjust this to your actual user store) @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password("{noop}" + SECURE_ADMIN_PASSWORD).roles("ADMIN") .and() .withUser("user").password("{noop}userpass").roles("USER"); } }
3. Check for Common Pitfalls
If your app still won't start, verify these common issues:
- Missing
@Configurationon WebSocket config: Spring won't recognize the config class without this annotation, leading to conflicts or unapplied rules. - Dependency mismatches: Ensure you have compatible versions of
spring-boot-starter-websocketandspring-boot-starter-securityin your build file. For Maven, add these dependencies if missing:<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies> - Deprecated
WebSecurityConfigurerAdapter(Spring Boot 2.7+): If you're using a newer Spring Boot version, replaceWebSecurityConfigurerAdapterwithSecurityFilterChainto avoid compatibility issues. Here's the updated version:@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig { private static final String SECURE_ADMIN_PASSWORD = "rockandroll"; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .formLogin(form -> form .loginPage("/index.html") .loginProcessingUrl("/login") .defaultSuccessUrl("/dashboard.html", true) .permitAll() ) .authorizeHttpRequests(auth -> auth .requestMatchers("/css/**", "/js/**", "/index.html").permitAll() .requestMatchers("/ws/**", "/stomp/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ); return http.build(); } @Bean public UserDetailsService userDetailsService() { UserDetails admin = User.withUsername("admin") .password("{noop}" + SECURE_ADMIN_PASSWORD) .roles("ADMIN") .build(); UserDetails user = User.withUsername("user") .password("{noop}userpass") .roles("USER") .build(); return new InMemoryUserDetailsManager(admin, user); } }
Final Notes
The key is to separate HTTP security (handles login, page access) from WebSocket security (handles message/subscription permissions) and ensure the handshake endpoint isn't blocked by your HTTP rules. Once you adjust these, your app should start up without issues and enforce WebSocket authorization correctly.
内容的提问来源于stack exchange,提问作者gstackoverflow

