如何在Spring 5.3及更高版本中使用Stomp和SockJS处理CORS来源?

12

我正在开发一个服务器应用程序,它同时使用REST端点和SockJS WebSocket。在Spring 5.2及以下版本中,这个应用程序可以正常运行。

然而,自从发布5.3版本以来org.springframework.web.cors.CorsConfiguration中出现了以下方法:

    public void validateAllowCredentials() {
        if (this.allowCredentials == Boolean.TRUE &&
                this.allowedOrigins != null && this.allowedOrigins.contains(ALL)) {

            throw new IllegalArgumentException(
                    "When allowCredentials is true, allowedOrigins cannot contain the special value \"*\"" +
                            "since that cannot be set on the \"Access-Control-Allow-Origin\" response header. " +
                            "To allow credentials to a set of origins, list them explicitly " +
                            "or consider using \"allowedOriginPatterns\" instead.");
        }
    }

到目前为止,我的套接字配置如下:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // prefix for the client to send messages to the server
        config.setApplicationDestinationPrefixes("/app");
        // prefix for the client to receive broadcasted messages from the server
        config.enableSimpleBroker("/topic");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // defines the url of the socket so the client can connect to it
        registry.addEndpoint("/socketendpoint").setAllowedOrigins("*").withSockJS();
    }
} 

现在我面临一个真正的问题:

  • 如果我在WebSocketConfiguration中保留setAllowedOrigins("*"),那么我将面对在validateAllowCredentials中抛出的错误。
  • 如果我删除setAllowedOrigins("*"),那么SockJS客户端将收到一个Error during WebSocket handshake: Unexpected response code: 403

我不知道原始域名在编译时是什么。

我已经尝试了一个Cors Filter和一个Cors Configuration,它们使用典型的“返回在请求中找到的origin头作为allow-origin”模式来规避allow-origin:"*",但有些SockJS请求没有分配origin头...

我该如何解决这个问题?


对于没有 Origin 请求头的请求,只需在响应中不发送 Access-Control-Allow-Origin 头—因为无论这些请求来自哪里,它们都不是来自将在响应中寻找 Access-Control-Allow-Origin 头的浏览器。唯一有用于 Access-Control-Allow-Origin 头的用户代理,甚至浏览器也只关心由浏览器本身添加 Origin 头的请求的响应。因此,任何缺少 Origin 头的请求都不需要在响应中使用 Access-Control-Allow-Origin。 - sideshowbarker
你能找到解决方案了吗? - Piotr
我们选择延迟依赖升级。最近在Spring存储库上有一次提交解决了这个问题,它应该包含在即将发布的版本中之一;不确定它是否已经发布。 - Martin Häusler
2个回答

27

未来参考,在最新的春季更新中,现在有一个方法setAllowedOriginPatterns可以解决这个问题:

 registry.addEndpoint("/socketendpoint").setAllowedOriginPatterns("*").withSockJS();

2
对我来说,它修复了错误,但是我不再收到其他Spring应用程序的任何消息。它发送了一条消息,但是没有接收到。而且它在早期的Spring Boot版本(2.2及更早版本)中可以正常工作。 - CptDayDreamer
嗨,我正在尝试使用corsfilter(在spring security中)和websocketconfig中的“setAllowedOriginPatterns(“*”)”来访问“/ websocket”端点。但是,如果两者都保留,则会出现“Access-Control-Allow-Origin中的多个值”,如果从其中一个中删除它,则会显示“没有Access-Control-Allow-Origin标头”或403错误。我该如何访问websocket端点? - Manoj Majumdar

4

从文档中

配置允许的 Origin 头值。此检查主要设计为浏览器客户端使用。没有任何防止其他类型的客户端修改 Origin 头的值。当启用 SockJS 并限制源头时,不允许检查请求来源的传输类型(基于 Iframe 的传输)将被禁用。因此,在限制源头时不支持 IE 6 至 9。 每个提供的允许来源都必须以"http://"、"https://"开头或为"*"(表示允许所有来源)。默认情况下,只允许同源请求(空列表)。自:4.1.2 参见:RFC 6454: Web Origin 概念,SockJS 支持的浏览器传输协议

您的代码

registry.addEndpoint("/socketendpoint").setAllowedOrigins("*").setAllowedOrigins().withSockJS();

应该是

 registry.addEndpoint("/socketendpoint").setAllowedOrigins("*").withSockJS();

抱歉,原问题中有一个错误;在复制和剪辑代码片段的过程中,它可能已经混进去了。现在已经修复了。 - Martin Häusler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接