如何在订阅频道时检查websocket用户是否经过身份验证?

时间:2017-12-19 20:36:45

标签: java spring spring-mvc websocket spring-websocket

我有websocket配置类:

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

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

以及ClientInboundChannel

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.setInterceptors(new ChannelInterceptorAdapter() {

        @Override
        public Message<?> preSend(Message<?> message, MessageChannel channel) {

            StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

            final String xAuthToken = accessor.getFirstNativeHeader(ManipulatesHeaders.X_AUTH_TOKEN_HEADER);

            if (xAuthToken == null) {
                return message;
            }

            final UserDetails userDetails = authService.getUserDetails(xAuthToken);

            if (StompCommand.CONNECT == accessor.getCommand()) {
                final WebSocketPrincipal principal = (...)

                userRegistry.registerUser(principal, message);
                accessor.setUser(principal);
            }

            return message;
        }
    }
}

现在,我想向订阅特定频道的每个用户发送一个欢迎消息。很明显,可以通过创建一个实现ApplicationListener<SessionSubscribeEvent>并提供

的类来实现
@Override
    public void onApplicationEvent(final SessionSubscribeEventevent) {
      StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
}

第二种方法是在上述ClientInboundChannel中执行类似的事情(它是相同的)。

问题是,当用户发送stomp simpUser时,message中没有SUBSCRIBE标头。

进程如下:用户发送stomp CONNECT,执行此行:accessor.setUser(principal)此时message已正确设置simpUser标头。但是,当SUBSCRIBE收到踩preSend消息时,StompHeaderAccessor没有simpUser标头。因此,我无法评估用户是否已经过身份验证。

那么如何检查发送SUBSCRIBE消息的用户是否已经过身份验证? (以及经过身份验证的用户不发送simpUser标头)

的原因

1 个答案:

答案 0 :(得分:1)

在您的websocket配置类中,将您的扩展名更改为AbstractSecurityWebSocketMessageBrokerConfigurer

然后您可以按如下方式设置安全性:

@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry message) {
    message
      .nullDestMatcher().permitAll()
      .simpDestMatchers("/app/**").authenticated()
      .simpSubscribeDestMatchers("/topics/**").authenticated()
      .anyMessage().denyAll();
}

如果收到错误Could not verify the provided CSRF token because your session was not found,则必须覆盖websocket配置类中的`sameOriginDisabled

  @Override
  protected boolean sameOriginDisabled() {
      return true;
  }

有关websocket安全性的更多信息:

https://docs.spring.io/spring-security/site/docs/current/reference/html/websocket.html