Spring Boot与Angular集成Spring Security时WebSocket连接被禁问题
问题排查与解决方案
核心原因分析
Postman能正常访问但Angular客户端报403,本质是Spring Security对跨域WebSocket请求的鉴权逻辑和普通HTTP请求存在差异,要么是Angular端未携带正确的认证/校验信息,要么是Spring Security配置未放行WebSocket相关端点。
具体排查点与解决步骤
1. 放行WebSocket端点的Spring Security配置
Spring Security默认拦截所有请求,需明确放行WebSocket握手端点及STOMP相关路径:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() // 握手阶段可临时禁用CSRF,或配置令牌传递(见下文) .authorizeRequests() .antMatchers("/socket/**", "/topic/**", "/queue/**").permitAll() // 替换为你的实际WebSocket端点 .anyRequest().authenticated(); } }
若需保留CSRF校验,Angular端需在连接时携带CSRF令牌:
// Angular WebSocketService中添加令牌获取逻辑 private getCsrfToken(): string { const cookie = document.cookie.split('; ') .find(row => row.startsWith('XSRF-TOKEN=')); return cookie ? cookie.split('=')[1] : ''; } // 连接时设置请求头 this.stompClient = Stomp.over(new SockJS('/socket')); this.stompClient.connect({ 'X-XSRF-TOKEN': this.getCsrfToken() }, (frame) => { // 连接成功后的订阅逻辑 });
2. 跨域(CORS)配置适配WebSocket
Angular与Spring Boot跨域时,需确保CORS配置允许WebSocket的预检请求(OPTIONS)及相关头:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:4200") // Angular运行地址 .allowedMethods("GET", "POST", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }
同时在SecurityConfig中启用CORS支持:
http.cors().and().csrf().disable();
3. 认证信息传递(若需用户认证)
如果WebSocket需要用户身份校验,Postman可能手动携带了认证头(如JWT),但Angular端未传递。需在连接时附加认证令牌:
// 从localStorage或服务中获取JWT令牌 const authToken = localStorage.getItem('authToken'); this.stompClient.connect({ 'Authorization': `Bearer ${authToken}` }, (frame) => { // 连接成功逻辑 });
并在Spring Boot的WebSocket配置中添加拦截器处理认证:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(new ChannelInterceptor() { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); if (StompCommand.CONNECT.equals(accessor.getCommand())) { String authHeader = accessor.getFirstNativeHeader("Authorization"); if (authHeader != null) { String token = authHeader.replace("Bearer ", ""); // 此处添加JWT校验逻辑,将认证信息存入SecurityContext Authentication auth = jwtValidator.validateToken(token); SecurityContextHolder.getContext().setAuthentication(auth); } } return message; } }); } }
4. 端点路径一致性检查
确保Angular端连接的路径与Spring Boot配置完全一致,比如Spring Boot配置的是/socket,Angular端不能写成/ws/socket这类错误路径。
内容的提问来源于stack exchange,提问作者thomas prevost
相关产品推荐
相关产品推荐

