You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway集成Spring Security时无法建立WebSocket连接

无法通过Spring Cloud Gateway建立WebSocket连接

我正在开发一个依赖WebSocket连接的应用,已完成包含WebSocket配置的Spring Boot微服务notification-service,并通过集成了Spring Security的gateway-service(端口8747)暴露该微服务的所有API。

前端测试代码

用于测试WebSocket连接的前端代码如下:

<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
    <script type="text/javascript">
            var stompClient = null;
            const LOCAL_URL = 'http://localhost:8747/websocket/notification-service/ws';

            var socket = new SockJS(LOCAL_URL);
            
            stompClient = Stomp.over(socket);
            stompClient.connect({}, function(frame) {
                console.log(frame);
                stompClient.subscribe('/topic/notification', function(result) {
                    show(JSON.parse(result.body));
                });
            });

            function sendMessage() {
                var text = document.getElementById('text').value;
                stompClient.send("/app/application", {},
                  JSON.stringify({'text':text}));
            }
            
            function show(message) {
                var response = document.getElementById('messages');
                var p = document.createElement('p');
                p.innerHTML= "message: "  + message.message;
                response.appendChild(p);
            }
        </script>
</head>
<body>
<div>
    <div>
        <button id="sendMessage" onclick="sendMessage();">Send</button>
        <input type="text" id="text" placeholder="Text"/>
    </div>
    <br />
    <div>
        <button id="sendPrivateMessage" onclick="sendPrivateMessage();">Send Private</button>
        <input type="text" id="privateText" placeholder="Private Message"/>
        <input type="text" id="to" placeholder="To"/>
    </div>
    <br />
    <br />
    <br />

        <div id="messages"></div>

</div>

</body>
</html>

Gateway服务配置

Spring Security配置

已将WebSocket相关端点加入白名单:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    private static final String[] AUTH_WHITE_LIST = {
        "/websocket/sds-notification-service/**"
    };

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        return http
            .csrf(ServerHttpSecurity.CsrfSpec::disable)
            .authorizeExchange(exchanges -> exchanges.pathMatchers(AUTH_WHITE_LIST)
                    .permitAll()
                    .anyExchange().authenticated())
            .build();
    }
}

全局响应过滤器

@Configuration
public class GlobalResponseFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            var response = exchange.getResponse();
            var request = exchange.getRequest();
            response.getHeaders().set("Access-Control-Allow-Credentials", "true");
            response.getHeaders().set("Access-Control-Allow-Origin", request.getHeaders().getOrigin());
            exchange.mutate().response(response).build();
        }));
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

自定义权限验证过滤器

我还实现了一个用于权限验证的AuthorizationFilter,代码如下:

@Component
public class AuthorizationFilter extends AbstractGatewayFilterFactory<AuthorizationFilter.Config> {

    public AuthorizationFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> ReactiveSecurityContextHolder.getContext()
            .map(securityContext -> {
                if (someValidateLogic()) {
                    return chain.filter(exchange);
                } else {
                    return Mono.error(new AuthorizationServiceException(HttpStatus.FORBIDDEN.toString()));
                }
            })
            .flatMap(classMono -> classMono)
            .then());
    }
}

问题描述

当前无法建立WebSocket连接,控制台报错。但移除上述自定义AuthorizationFilter后,WebSocket连接可正常建立,推测是过滤器顺序配置有误导致的问题。

内容的提问来源于stack exchange,提问作者iuhettiarachchi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 22:04:55