Sun*_*ezz 6 java spring unit-testing session-cookies spring-websocket
我有一个带有 Spring-Security/Session 和 Spring-Websocket 的 Spring Boot 2.2 MVC 应用程序。
它被配置为仅在经过身份验证时允许 websocket 连接。
以下是在单元测试中创建 Websocket 客户端的推荐方法。(至少我在 spring 文档中看到过这个)
private StompSession createWebsocket() throws InterruptedException, ExecutionException, TimeoutException {
List<Transport> transports = new ArrayList<>(1);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(transports));
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSession stompSession = stompClient.connect("ws://localhost:" + port + "/app", new StompSessionHandlerAdapter() {}).get(1, SECONDS);
return stompSession;
}
Run Code Online (Sandbox Code Playgroud)
但是,这样我在日志中得到了异常,因为 Spring 重定向到登录页面,这通常是好的和需要的,因为 Websocket 请求未经身份验证。
日志确认:
2019-11-12 18:03:32.487 DEBUG 19592 --- [o-auto-1-exec-3] o.s.s.w.u.m.AndRequestMatcher : All requestMatchers returned true
2019-11-12 18:03:32.487 DEBUG 19592 --- [o-auto-1-exec-3] o.s.s.w.DefaultRedirectStrategy : Redirecting to 'http://localhost:51599/login'
...
2019-11-12 18:03:32.513 DEBUG 19592 --- [o-auto-1-exec-4] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2019-11-12 18:03:32.514 ERROR 19592 --- [cTaskExecutor-1] o.s.w.s.s.c.DefaultTransportRequest : No more fallback transports after TransportRequest[url=ws://localhost:51599/app/299/6928331c14b94beba4315294661970c3/websocket]
javax.websocket.DeploymentException: The HTTP response from the server [200] did not permit the HTTP upgrade to WebSocket
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServerRecursive(WsWebSocketContainer.java:437) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27]
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServerRecursive(WsWebSocketContainer.java:395) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27]
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:197) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27]
at org.springframework.web.socket.client.standard.StandardWebSocketClient.lambda$doHandshakeInternal$0(StandardWebSocketClient.java:151) ~[spring-websocket-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264) [?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java) [?:?]
at java.lang.Thread.run(Thread.java:844) [?:?]
Run Code Online (Sandbox Code Playgroud)
虽然没有任何地方记录如何验证 websocket 客户端,除了会话头之外,我尝试手动登录,检索会话 cookie 以将其设置在 WS 连接/握手头中,但没有运气,因为 MockMvc 似乎没有存储或在标题中设置任何 cookie。
2019-11-12 18:03:32.487 DEBUG 19592 --- [o-auto-1-exec-3] o.s.s.w.u.m.AndRequestMatcher : All requestMatchers returned true
2019-11-12 18:03:32.487 DEBUG 19592 --- [o-auto-1-exec-3] o.s.s.w.DefaultRedirectStrategy : Redirecting to 'http://localhost:51599/login'
...
2019-11-12 18:03:32.513 DEBUG 19592 --- [o-auto-1-exec-4] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2019-11-12 18:03:32.514 ERROR 19592 --- [cTaskExecutor-1] o.s.w.s.s.c.DefaultTransportRequest : No more fallback transports after TransportRequest[url=ws://localhost:51599/app/299/6928331c14b94beba4315294661970c3/websocket]
javax.websocket.DeploymentException: The HTTP response from the server [200] did not permit the HTTP upgrade to WebSocket
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServerRecursive(WsWebSocketContainer.java:437) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27]
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServerRecursive(WsWebSocketContainer.java:395) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27]
at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:197) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27]
at org.springframework.web.socket.client.standard.StandardWebSocketClient.lambda$doHandshakeInternal$0(StandardWebSocketClient.java:151) ~[spring-websocket-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264) [?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java) [?:?]
at java.lang.Thread.run(Thread.java:844) [?:?]
Run Code Online (Sandbox Code Playgroud)
请求打印的输出:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /perform_login
Parameters = {email=[user@test.com], pw=[test123], _csrf=[933cd6ad-0c81-4539-82a5-b184babcad84]}
Headers = [Accept:"application/x-www-form-urlencoded"]
Body = <no character encoding set>
Session Attrs = {userid=88, SPRING_SECURITY_CONTEXT=org.springframework.security.core.context.SecurityContextImpl@c08a487f: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@c08a487f: Principal: com.package.UserDetails@7ca802e3; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: FULL_AUTH, username=user@test.com}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [X-Redirect:"/", Content-Type:"application/json", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = application/json
Body = {"code":200, "status":"ok"}
Forwarded URL = null
Redirected URL = null
Cookies = []
Run Code Online (Sandbox Code Playgroud)
应用程序就像一个魅力,登录正在工作,websocket 也在工作。
正常的登录以 cookie 响应,一切正常。
与 Websocket 连接相同的异常(但没有答案)
与 MockMVC-Cookies 的行为相同(没有一个答案有效)