content: package net.alex9849.cocktailpi.config.websocket;
  
  import net.alex9849.cocktailpi.config.JwtUtils;
  import net.alex9849.cocktailpi.config.security.UserDetailsServiceImpl;
  import net.alex9849.cocktailpi.model.user.ERole;
  import net.alex9849.cocktailpi.model.user.User;
  import net.alex9849.cocktailpi.service.WebSocketService;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.core.Ordered;
  import org.springframework.core.annotation.Order;
  import org.springframework.messaging.Message;
  import org.springframework.messaging.MessageChannel;
  import org.springframework.messaging.simp.config.ChannelRegistration;
  import org.springframework.messaging.simp.config.MessageBrokerRegistry;
  import org.springframework.messaging.simp.stomp.StompCommand;
  import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
  import org.springframework.messaging.support.ChannelInterceptor;
  import org.springframework.messaging.support.MessageHeaderAccessor;
  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  import org.springframework.security.core.Authentication;
  import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
  import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
  import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
  
  import java.util.List;
  
  @Configuration
  @EnableWebSocketMessageBroker
  @Order(Ordered.HIGHEST_PRECEDENCE + 99)
  public class WebSocketAuthenticationConfig implements WebSocketMessageBrokerConfigurer {
  
      @Autowired
      private JwtUtils jwtUtils;
  
      @Autowired
      private UserDetailsServiceImpl userDetailsService;
  
      @Override
      public void configureMessageBroker(MessageBrokerRegistry config) {
          config.enableSimpleBroker("/topic", "/queue");
          config.setApplicationDestinationPrefixes("/app");
      }
  
      @Override
      public void registerStompEndpoints(StompEndpointRegistry registry) {
          registry.addEndpoint("/websocket/").setAllowedOriginPatterns("*");
          registry.addEndpoint("/websocket/").setAllowedOriginPatterns("*").withSockJS()
                  .setClientLibraryUrl("https://cdn.jsdelivr.net/npm/sockjs-client@1.5.0/dist/sockjs.min.js");
      }
  
      @Override
      public void configureClientInboundChannel(ChannelRegistration registration) {
          registration.interceptors(new WebSocketTopicSubscriptionInterceptor(WebSocketService.WS_ACTIONS_STATUS_DESTINATION, ERole.ROLE_ADMIN));
          registration.interceptors(new WebSocketTopicSubscriptionInterceptor(WebSocketService.WS_ACTIONS_LOG_DESTINATION, ERole.ROLE_ADMIN));
          registration.interceptors(new ChannelInterceptor() {
              @Override
              public Message<?> preSend(Message<?> message, MessageChannel channel) {
                  StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
                  if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                      List<String> authorization = accessor.getNativeHeader("Authorization");
                      if(authorization.isEmpty()) {
                          return message;
                      }
                      String token = jwtUtils.parseJwt(authorization.get(0));
                      if(token == null || !jwtUtils.validateJwtToken(token)) {
                          return message;
                      }
                      User user = userDetailsService.loadUserById(jwtUtils.getUserIdFromJwtToken(token));
                      Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
                      accessor.setUser(authentication);
                  }
                  return message;
              }
          });
      }
  }
  