【发布时间】:2017-01-18 05:21:18
【问题描述】:
让 Spring Boot 1.4 + Spring 4.x + Spring Security 4.x WebSocket 身份验证与基于无状态令牌的身份验证一起工作似乎是一次冒险!
到目前为止,据我了解,SockJS 无法使用令牌设置 Authentication 标头,因为浏览器不会将该 API 暴露给 Javascript(请参阅 https://github.com/sockjs/sockjs-client/issues/196)。我已经解决了这个问题,方法是按照上述问题的建议在查询参数中设置身份验证令牌,然后使用 Spring HandshakeHandler 和 determineUser() 将查询参数映射到用户实体。丑陋且不太安全,但至少它适用于 WebSockets。
但是,当 SockJS 回退到另一种机制时,例如XHR 流,相同的机制不再起作用。 HandshakeInterceptor 可以访问请求,并且可以从查询参数中获取身份验证,但是对于非 WebSocket 握手,永远不会调用 HandshakeHandler 上的 determineUser。
到目前为止,我得到的最接近的是绕过内置的连接级 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 “看到”从查询参数中提取的身份验证?
【问题讨论】:
标签: spring spring-mvc authentication spring-security spring-boot