Spring Boot,Websockets无法从Session获取用户(即java.security.Principal)

Chr*_*son 5 java session spring-boot spring-websocket

与工作Spring Boot 1.2.1.RELEASESpring Websockets.有一个部署运行时问题,当运行嵌入式时Jetty 9,我不能java.security.Principal成功地伪装用户()当app部署在除localhost之外的任何其他地方.

我咨过过

下面的配置(我相信)已经"升级"了一个请求

@Configuration
@EnableWebSocketMessageBroker
@EnableScheduling
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    // see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-handle-broker-relay
    // requires an external broker like AMQP or RabbitMQ
    //registry.enableStompBrokerRelay("/queue/", "/topic/");

    // XXX This might wind up being the impl we actually deploy; but be aware it has certain constraints
    // see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-message-flow
    registry.enableSimpleBroker("/queue/", "/topic/");
    registry.setApplicationDestinationPrefixes("/app");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/cards").setHandshakeHandler(new UserHandler()).withSockJS();
}

// cheat; ensure that we have a Principal w/o relying on authentication
class UserHandler extends DefaultHandshakeHandler {

    @Override
    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
                    Map<String, Object> attributes) {
        return new TestPrincipal("bogus");
    }
}
Run Code Online (Sandbox Code Playgroud)

这是校长......

public class TestPrincipal  implements Principal {

private final String name;


public TestPrincipal(String name) {
    this.name = name;
}

@Override
public String getName() {
    return this.name;
}

}
Run Code Online (Sandbox Code Playgroud)

但这是我收到的例外......

Logger=org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler Type=ERROR Message=Unhandled exception
org.springframework.messaging.simp.annotation.support.MissingSessionUserException: No "user" header in message
at org.springframework.messaging.simp.annotation.support.PrincipalMethodArgumentResolver.resolveArgument(PrincipalMethodArgumentResolver.java:42) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:127) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:100) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:451) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:443) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:82) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:412) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:350) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_05]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_05]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_05]
Run Code Online (Sandbox Code Playgroud)

我还应该考虑什么呢?

UPDATE

我现在可以在localhost部署中可靠地重现这一点.

有趣的是,STS 3.6.3在调试模式下使用时,我在第91行设置断点JettyRequestUpgradeStrategy

public JettyRequestUpgradeStrategy(WebSocketServerFactory factory) {
    Assert.notNull(factory, "WebSocketServerFactory must not be null");
    this.factory = factory;
    this.factory.setCreator(new WebSocketCreator() {
        @Override
        public Object createWebSocket(ServletUpgradeRequest request, ServletUpgradeResponse response) {
            // Cast to avoid infinite recursion
            return createWebSocket((UpgradeRequest) request, (UpgradeResponse) response);
        }
Run Code Online (Sandbox Code Playgroud)

然后继续到第41行的另一个断点 PrincipalMethodArgumentResolver

@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
    Principal user = SimpMessageHeaderAccessor.getUser(message.getHeaders());
    if (user == null) {
        throw new MissingSessionUserException(message);
    }
    return user;
}
Run Code Online (Sandbox Code Playgroud)

usernull.有竞争条件吗?例如,套接字必须从请求中获取用户的时间限制吗?