首页 > 解决方案 > 如何使用spring stomp websocket拒绝用户订阅或取消订阅服务器端的用户

问题描述

我试图在用户被管理员禁止时强制取消订阅,并在用户被禁止时阻止该用户订阅。禁令状态保存在我的数据库中。我目前有一个拦截器来执行阻塞,preSend但是当我抛出异常时连接关闭。无论如何在不关闭套接字连接的情况下拒绝订阅消息吗?

 @Override
  public Message<?> preSend(@NonNull Message<?> message, @NonNull MessageChannel channel) {
    StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
    if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
      checkIsBanned(headerAccessor.getDestination(), headerAccessor.getUser());
    }
    return message;
  }

  private void checkIsBanned(String destination, Principal principal) {
    if (destination == null || !destination.matches(CHAT_TOPIC_REGEX)) {
      return;
    }
    String errorMessage = resourceBundle.getMessage("err.channel.banned");
    if (!(principal instanceof OAuth2Authentication) || !(((OAuth2Authentication) principal).getPrincipal() instanceof SUserDetails)) {
      throw new MessagingException(errorMessage);
    }
    String channelId = destination.split("/")[3];
    Long profileId = getProfileId(principal);
    if (profileId == null) {
      throw new MessagingException(errorMessage);
    }
    channelUserRepo.findByChannelIdAndUserId(channelId, profileId).filter(ChannelUser::isBanned).orElseThrow(() -> new MessagingException(errorMessage));
  }

  private Long getProfileId(Principal principal) {
    return ((SUserDetails) ((OAuth2Authentication) principal).getPrincipal()).getProfileId();
  }

当管理员禁止用户时,我还尝试通过让用户退出userRegistry并删除他的订阅来强制取消订阅,但这没有用。有没有办法做到这一点?

标签: springspring-bootspring-websocket

解决方案


我想我设法通过仅返回 null 来拒绝订阅,preSend它将忽略订阅消息而不是抛出错误。您还可以通过套接字向用户发送通知来通知用户。

public ChatInterceptor(ResourceBundle resourceBundle, ChannelUserRepository channelUserRepo, @Lazy SimpMessagingTemplate socket) {
    this.resourceBundle = resourceBundle;
    this.channelUserRepo = channelUserRepo;
    this.socket = socket;
  }

  @Override
  public Message<?> preSend(@NonNull Message<?> message, @NonNull MessageChannel channel) {
    StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
    if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
      if (checkIsBanned(headerAccessor.getDestination(), headerAccessor.getUser())) {
        socket.convertAndSendToUser(getSocketUsername(headerAccessor.getUser()), ServicePath.NOTIFICATION,
            new SocketResponse(resourceBundle.getMessage("err.channel.banned"), ERROR));
        return null;
      }
    }
    return message;
  }

推荐阅读