Gloria
Gloria

Reputation: 1046

How to retrieve the current logged in user in a websocket controller

I am trying to obtain the currently authenticated user in the controller for websockets. The problem is, I cannot access the user using SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId(). I have tried to give Principal as a parameter to the method but it returns principal null. Security configuration:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/connect").setAllowedOrigins("*");
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic/messages");
        registry.setApplicationDestinationPrefixes("/ws");
    }

}

Controller for websocket:

@Controller
public class MessageController {

    @Autowired
    private Consumer consumer;

    @Autowired
    private Utils utils;

    @Autowired
    private PersonService personService;

    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;
    String destination = "/topic/messages";

    ExecutorService executorService =
            Executors.newFixedThreadPool(1);
    Future<?> submittedTask;

    @MessageMapping("/start")
    public void startTask(Principal principal){

        // Here, I would like to get the logged in user
        // If I use principal like this: principal.getName() => NullPointerException


        if ( submittedTask != null ){
            simpMessagingTemplate.convertAndSend(destination,
                    "Task already started");
            return;
        }
        simpMessagingTemplate.convertAndSendToUser(sha.getUser().getName(), destination,
                "Started task");
        submittedTask = executorService.submit(() -> {
            while(true){
simpMessagingTemplate.convertAndSend(destination,
//                            "The calculated value " + val + " is equal to : " + max);

            }
        });
    }

How can I get the authenticated user? I needed it to check when to start the task for the web socket

Upvotes: 0

Views: 1181

Answers (1)

ironside
ironside

Reputation: 61

Try to implement ChannelInterceptor, that need to be registrated in Config file (class that implements WebSocketMessageBrokerConfigurer)

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer  {

    private final ChannelInterceptor serverPushInBoundInterceptor;

    @Autowired
    public WebSocketConfig(@Qualifier("serverPushInBoundInterceptor") ChannelInterceptor serverPushInBoundInterceptor) {
        this.serverPushInBoundInterceptor = serverPushInBoundInterceptor;
    }

    ....

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(serverPushInBoundInterceptor);
    }
}

@Component("serverPushInBoundInterceptor")
public class ServerPushInBoundInterceptor implements ChannelInterceptor {
    private static final Logger log = LoggerFactory.getLogger(ServerPushInBoundInterceptor.class);


    @Override
    @SuppressWarnings("NullableProblems")
    public Message<?> postReceive(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

        if (StompCommand.CONNECT.equals(Objects.requireNonNull(accessor).getCommand())) {
            List<String> authorization = accessor.getNativeHeader("Authorization");
            if (authorization != null && !authorization.isEmpty()) {
                String auth = authorization.get(0).split(" ")[1];
                System.out.println(auth);
                try {

                    // find Principal
                    Principal principal = ...
                    accessor.setUser(new UsernamePasswordAuthenticationToken(principal, principal.getCredentials(), principal.getAuthorities()));

                } catch (Exception exc) {
                    log.error("preSend", exc);
                }
            }
        }

        return message;
    }

}

Upvotes: 0

Related Questions