Spring 4.x基于令牌的WebSocket SockJS后备身份验证

时间:2016-09-10 02:53:53

标签: spring spring-mvc authentication spring-security spring-boot

获取Spring Boot 1.4 + Spring 4.x + Spring Security 4.x使用基于无状态令牌的身份验证的WebSocket身份验证似乎是一次冒险!

到目前为止,据我所知,SockJS无法使用令牌设置Authentication标头,因为浏览器不会将该API暴露给Javascript(请参阅https://github.com/sockjs/sockjs-client/issues/196)。我已经解决了这个问题,方法是在查询参数中按照上述问题的建议设置身份验证令牌,然后使用带有HandshakeHandler的Spring determineUser()将查询参数映射到User实体。丑陋且不太安全,但至少它适用于WebSockets。

然而,当SockJS回归到另一种机制时,例如XHR流媒体,相同的机制不再有效。 HandshakeInterceptor可以访问请求并可以从查询参数获取身份验证,但determineUser上的 HandshakeHandler永远不会被调用非WebSocket握手

我到目前为止最接近的是绕过内置的连接级Spring机制来确定身份验证。相反,我通过在客户端的Stomp标头中设置身份验证令牌来设置消息级别,例如:

stompClient.send("/wherever", {token: 'token'}, ...);

并使用通道拦截器在服务器端提取它:

configureClientInboundChannel(ChannelRegistration registration) {
  registration.setInterceptors(new ChannelInterceptorAdapter() {
     Message<*> preSend(Message<*> message,  MessageChannel channel) {
      StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
      // not documented anywhere but necessary otherwise NPE in StompSubProtocolHandler!
      accessor.setLeaveMutable(true);
      List tokenList = accessor.getNativeHeader("token");
      if(tokenList == null || tokenList.size < 1) {
        return message;
      }
      Principal yourAuth = [...];
      return MessageBuilder.createMessage(message.payload, accessor.messageHeaders)
    }
  })

现在Spring将Principal注入任何需要它的控制器方法,但user 仍未保存到websocket会话,因此消息仍然无法发送到特定用户。

如何让Spring“查看”从查询参数中提取的身份验证?

1 个答案:

答案 0 :(得分:0)

使用Stomp Headers

绕过内置的连接级Spring机制来确定身份验证。相反,通过在客户端的Stomp标头中设置身份验证令牌,将其设置为消息级别。请参阅我在此概述的方法:

https://stackoverflow.com/a/39456274/430128