如何通过 JWT 验证 websocket 聊天

How to authenticate websocket chat by JWT

我有一个websockets聊天的功能性项目已经在运行,现在我需要通过JWT实现身份验证。这是请求的流程

  1. 客户端连接到 ws://localhost:port/chatting
  2. 客户端订阅自己的收件箱,以便接收来自其他客户端的消息:/user/{userId}/queue/chatting
  3. 客户端可以通过在正文中指定向/app/message中的其他用户发送消息: { 'message': msg, 'from': "userId", 'to': "recipientId" },系统会将他们重定向到 /user/{recipientId}/queue/chatting

我想保护:

  1. 用户必须进行身份验证才能进行握手
  2. 用户必须是 "userId" 才能订阅 /user/"userId"/queue/chatting,这样其他用户就可以'无法访问它。
  3. 用户必须是 "userId" 才能 发送 消息给另一个用户 "userId" in from inside body

首先,可以通过在 WebSecurityConfig 中配置相同的方式来添加身份验证,添加一个自定义 JwtRequestFilter 来解析您的 JWT 令牌并为该请求设置身份验证上下文。

同样的一个很好的参考:create-apis-with-jwt-authorization-using-spring-boot

关于 2 和 3,Springboot 不允许公开 STOMP 注册的动态端点,因此您必须公开 /user/queue/chatting 并且客户端必须直接订阅它。但是,使用执行此操作的 convertAndSendToUser(userId, destination, payload) you can send the message based on the userId. This function internally calls this function this.destinationPrefix(/user) + user(/username) + destination(/queue/chatting) 因此您可以看到变量 user 已作为最终目的地的前缀,您可以传递 userId 而不是 userName.

参考:simpMessagingTemplate.convertAndSendToUser

但请注意,在这种情况下,您必须将此会话的用户名设置为 userId 本身。这可以在您的自定义 JwtRequestFilter

中完成
private void populateSecurityContextHolder(HttpServletRequest request, String userId, List<SimpleGrantedAuthority> grantedAuthorities) {
        PreAuthenticatedAuthenticationToken authToken = new PreAuthenticatedAuthenticationToken(
                userId, null, grantedAuthorities);
        authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authToken);
        log.info("Authentication set for userId " + userId);
    }

因此,您的服务器可以根据它在消息中收到的 userId 发送消息。