带有STOMP的Spring MVC Websockets - 针对特定渠道进行身份验证

时间:2017-06-30 18:25:42

标签: spring spring-mvc websocket stomp spring-websocket

AbstractWebSocketMessageBrokerConfigurer(Spring Boot)中是否有办法拦截用户注册到特定频道?

我使用HandshakeHandler在registerStompEndpoints完成了基本身份验证:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
   HandshakeHandler handler = new DefaultHandshakeHandler() {
      @Override
      protected Principal determineUser(ServerHttpRequest request, 
            WebSocketHandler wsHandler, Map<String, Object> attributes) {
       Principal principal = request.getPrincipal();
       if (principal == null) {
         return () -> getPrincipal();
       }
       return principal;
     }
   };
   registry.addEndpoint("/websocket")
    .setHandshakeHandler(handler)
    .setAllowedOrigins("*").withSockJS();
}

现在我想阻止此用户注册'/ topic / admin / news',如果用户没有'admin'权限。我没有使用Spring Security。我希望在注册频道之前有一个拦截器。

作为替代方案,我想使用SimpMessagingTemplate仅从拥有该权限的频道向用户发送消息。有没有办法看到用户当前连接到我的stomp-connection?

1 个答案:

答案 0 :(得分:1)

public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.setInterceptors(new TopicSubscriptionInterceptor());
}

拦截器:

public class TopicSubscriptionInterceptor implements ChannelInterceptor {

private static Logger logger = org.slf4j.LoggerFactory.getLogger(TopicSubscriptionInterceptor.class);

@Override
public Message<?> postReceive(Message<?> message, MessageChannel chanenel) {
    return message;
}

@Override
public void postSend(Message<?> message, MessageChannel chanel, boolean sent) {
}

@Override
public boolean preReceive(MessageChannel channel) {
    return true;
}

@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
    StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
    if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand()) && headerAccessor.getHeader("simpUser") !=null &&  headerAccessor.getHeader("simpUser") instanceof UsernamePasswordAuthenticationToken) {
        UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) headerAccessor.getHeader("simpUser");
        if(!validateSubscription((User)userToken.getPrincipal(), headerAccessor.getDestination()))
        {
            throw new IllegalArgumentException("No permission for this topic");
        }
    }
    return message;
}

private boolean validateSubscription(User principal, String topicDestination)
{
    logger.debug("Validate subscription for {} to topic {}",principal.getUsername(),topicDestination);
    //Validation logic coming here
    return true;
}
}