如何在 websocket 控制器中检索当前登录的用户

Posted

技术标签:

【中文标题】如何在 websocket 控制器中检索当前登录的用户【英文标题】:How to retrieve the current logged in user in a websocket controller 【发布时间】:2022-01-03 18:12:22 【问题描述】:

我正在尝试在 websockets 控制器中获取当前经过身份验证的用户。问题是,我无法使用 SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId() 访问用户。 我试图将 Principal 作为方法的参数,但它返回主体 null。 安全配置:

@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");
    


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);

            
        );
    

如何获取经过身份验证的用户?我需要它来检查何时启动 Web 套接字的任务

【问题讨论】:

不要将代码发布为图像,而是作为代码发布,请添加您的完整控制器和安全配置。 @M.Deinum 修改了问题 你的 websocket 安全配置在哪里? 您的处理程序也错了,您将状态存储在控制器(submittedTask)上,这是错误的。 嗯以上。它被称为 WebSocketConfig 【参考方案1】:

尝试实现ChannelInterceptor,需要在Config文件中注册(实现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;
    


【讨论】:

以上是关于如何在 websocket 控制器中检索当前登录的用户的主要内容,如果未能解决你的问题,请参考以下文章

Cakephp 3 - 如何在验证过程中检索“表”类中的当前登录用户?

如何使用 Backand 检索当前登录的用户

在 web api 控制器中获取当前登录的用户

在 WebSocket 控制器中获取登录用户的 Principal

PHP websocket服务器和mysql连接

如何在firestore中检索当前auth用户的所有字段? - 科特林