通过SockJS进行的STOMP安全WebSocket升级失败,原因是无效的升级头null。

6
我正在开发一个使用Spring Security和WebSockets的Web应用程序。我能够在本地机器上使用WebSockets,从嵌入式Tomcat的JAR运行Spring Boot应用程序没有问题。但是,当我将相同的JAR/项目上传到CloudFoundry或OpenShift(并作为可执行JAR运行)时,在建立WebSocket连接时的协议升级失败。
我制作了一个小型示例项目,演示了这个问题(至少在我尝试在我的机器或我的CloudFoundry或OpenShift帐户上时)。它在这里: https://github.com/shakuzen/spring-stomp-websocket-test 这是一个简化的、基础的示例,但我能够始终重现这个问题。日志中的错误消息是:
2014-10-20T00:46:36.69+0900 [App/0]   OUT 2014-10-19 15:46:36.698 DEBUG 32 --- [io-61088-exec-5] o.s.w.s.s.s.DefaultHandshakeHandler      : Invalid Upgrade header null

在此之前,DefaultHandshakeHandler 的 DEBUG 日志显示 Upgrade 标头丢失。但是,如果您查看使用 Chrome 开发者工具(或任何浏览器的等效工具)发送的请求,您将会看到请求不同。以下是发送的两个请求。

1

GET /hello/info HTTP/1.1
Host: sswss-test.cfapps.io
Connection: keep-alive
Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M=
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36
Accept: */*
Referer: http://sswss-test.cfapps.io/message
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,ja;q=0.6
Cookie: __VCAP_ID__=693dd6ff1b494f88a2c8567590da500dc44b4818746a45b28dd98a29b2607395; JSESSIONID=C5485065FE0A1DBCDF1F148A63D08FC2
DNT: 1

2

GET ws://sswss-test.cfapps.io/hello/863/olm1kojs/websocket HTTP/1.1
Host: sswss-test.cfapps.io
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M=
Upgrade: websocket
Origin: http://sswss-test.cfapps.io
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,ja;q=0.6
Cookie: __VCAP_ID__=693dd6ff1b494f88a2c8567590da500dc44b4818746a45b28dd98a29b2607395; JSESSIONID=C5485065FE0A1DBCDF1F148A63D08FC2
Sec-WebSocket-Key: 7bW1pg6f9axkVfqV21k/9w==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

似乎它正在使用第一个请求的标头并因此而失败。然而,当在我的本地机器上运行时,发送相同的两个请求(当然,是用localhost而不是sswss-test.cf.apps.io以及安全标头的不同值),但没有这个问题。我已经在Chrome和Firefox上尝试过了。
我链接的GitHub项目正在使用Spring Boot 1.2.0.M2,但我也测试了最新的发布版本(1.1.8.RELEASE)并得到了相同的结果。我还发现在搜索中,也许SockJS不能很好地处理相对URL,所以我尝试从控制台使用绝对URL运行连接命令:
var socket2 = new SockJS('http://sswss-test.cfapps.io/hello');

但不幸的是结果仍然相同。
欢迎任何建议或解决方案。随意分叉GitHub项目并尝试它(OpenShift有免费账户选项,因此您可以在那里免费部署以重新创建问题)。我将在此处复制项目的相关部分。
WebSocketConfig
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/queue/", "/topic/");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/hello").withSockJS();
    }
}

安全配置

我的实际应用程序正在使用Facebook进行身份验证,但我能够使用基本身份验证重现此问题,因此我不想浪费更多时间进行额外设置和增加复杂性。

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic()
            .and()
            //Configures url based authorization
            .authorizeRequests()
                // Anyone can access the urls
                .antMatchers("/").permitAll()
                //The rest of the our application is protected.
                .antMatchers("/**").authenticated();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("testuser").password("testpass").roles("USER").and()
                .withUser("adminuser").password("adminpass").roles("ADMIN","USER");
    }
}

1
这个问题有解决的进展了吗?我也在寻求解决方法。 - naoru
抱歉回复这么晚。我一直忙于工作和搬家,没有机会写出一个合适的回复。对我来说,问题在于端口。OpenShift和CloudFoundry只允许在特定端口上进行websocket连接。这就是为什么它在我的本地机器上可以工作,因为没有这样的限制。只需将特定端口添加到URL中即可使事情正常运行,但这会使URL变得丑陋。如果可能的话,这是我想要找到解决方案的下一个问题。我将尝试在接下来的几天内撰写一篇带有链接的适当答案。 - Tommy Ludwig
@TommyLudwig 啊!这正是 Stack Overflow 希望帮助消除的问题——你遇到了一个问题,你搜索并搜索,找到有人遇到了同样的问题。他们在 4 年前的论坛帖子上说,“算了,我自己解决了。” 你到底解决了什么,伙计?帮我们一下。 - Chris Baker
1个回答

1

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