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

Posted

技术标签:

【中文标题】如何在 Spring 5.3 及更高版本中使用 Stomp 和 SockJS 处理 CORS 起源?【英文标题】:How to handle CORS origins with Stomp and SockJS in Spring 5.3 and newer? 【发布时间】:2021-03-15 16:02:14 【问题描述】:

我正在开发一个同时使用 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();
    
 

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

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

我在编译时不知道源域。

我已经尝试了一个 Cors 过滤器和一个 Cors 配置,它们使用典型的“将您在请求中找到的 origin 标头返回为 allow-origin”模式,该模式通常用于规避 allow-origin: "*",但一些 SockJS 请求没有分配origin 标头...

我该如何解决这个问题?

【问题讨论】:

对于没有 Origin 请求标头的请求,不要在响应中发送 Access-Control-Allow-Origin 标头,因为无论这些请求来自哪里,它们re 不是来自将在响应中查找 Access-Control-Allow-Origin 标头的浏览器。唯一对 Access-Control-Allow-Origin 标头有任何用途的用户代理,甚至浏览器也只关心它只对浏览器本身添加了 Origin 标头的请求的响应。因此,任何缺少 Origin 标头的请求都不需要响应中的 Access-Control-Allow-Origin。 你能找到解决办法吗? 我们选择延迟依赖升级。 Spring 存储库最近已经提交了关于此问题的提交,它应该包含在即将发布的版本之一中;不知道它是否已经出来了。 【参考方案1】:

为了将来参考,随着最新的春季更新,现在有一个方法setAllowedOriginPatterns可以解决这个问题:

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

【讨论】:

对我来说,它修复了错误,但我不再收到其他 Spring 应用程序的任何消息。它发送一条消息,但没有收到任何消息。它适用于早期的 Spring Boot 版本(2.2 及更早版本) 嗨,我正在尝试使用 corsfilter(在 spring security 中)和“setAllowedOriginPatterns("*")”(在 websocketconfig 中)访问“/websocket”端点。但是,通过同时保留它会给出“'Access-Control-Allow-Origin' 中的多个值”并从其中一个中删除,它会显示“没有 Access-Control-Allow-Origin 标头”或 403 错误。如何访问 websocket 端点?【参考方案2】:

来自文档

配置允许的 Origin 标头值。这个检查主要是设计的 对于浏览器客户端。没有什么可以阻止其他类型的客户 修改 Origin 标头值。当启用 SockJS 和起源时 受到限制,不允许检查请求的传输类型 origin(基于 iframe 的传输)被禁用。因此,IE 6 当来源受到限制时,不支持到 9。 每个提供 允许的来源必须以“http://”、“https://”或“*”开头(表示 允许所有来源)。 默认情况下,只有相同来源的请求 被允许(空列表)。自从: 4.1.2 另见:RFC 6454: The Web Origin Concept , SockJS support transports by browser

你的代码

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

应该是

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

【讨论】:

对不起,原来的问题有错误;必须沿着复制粘贴的路线潜入代码 sn-p 并将其修剪回相关部分。现在已经修好了。

以上是关于如何在 Spring 5.3 及更高版本中使用 Stomp 和 SockJS 处理 CORS 起源?的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 11 及更高版本中使用 HttpClient 时如何跟踪 HTTP 303 状态代码?

如何使用支持库 25.0.0 及更高版本获取片段()

registerForRemoteNotificationTypes:iOS 8.0及更高版本不支持

如何使用 RxAlamofire 或 Alamofire 5 及更高版本检查相同的 DataRequest 是不是已经在进行中? [关闭]

如何在 android 2.3 及更高版本中获取当前启动器的包名?

如何在 Equinox 3.10 及更高版本中获取所有已加载的包