SimpUserRegistry 不包含任何会话对象

SimpUserRegistry doesnot contain any session objects

我是 Websockets 的新手。我一直在尝试使用 SimpUserRegistry 通过 Principal 查找会话对象。我编写了一个自定义握手处理程序来将匿名用户转换为经过身份验证的用户,并且我能够从 Websocket 会话对象访问主体名称。

自定义握手处理程序的代码如下所示


import java.security.Principal;

public class StompPrincipal implements Principal {
    private String name;

    public StompPrincipal(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}

处理程序

class CustomHandshakeHandlerTwo extends DefaultHandshakeHandler {
    // Custom class for storing principal
    @Override
    protected Principal determineUser(
            ServerHttpRequest request,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes
    ) {
        // Generate principal with UUID as name
        return new StompPrincipal(UUID.randomUUID().toString());
    }
}

但正如 等许多问题中所述,我无法直接注入 SimpUserRegistry

它抛出错误


Field simpUserRegistry  required a bean of type 'org.springframework.messaging.simp.user.SimpUserRegistry' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.messaging.simp.user.SimpUserRegistry' in your configuration.


所以我创建了一个配置 class 如下所示。


@Configuration
public class UsersConfig {
    final private SimpUserRegistry userRegistry = new DefaultSimpUserRegistry();

    @Bean
    @Primary
    public SimpUserRegistry userRegistry() {
        return userRegistry;
    }
}

现在我可以自动装配并使用它,但每次我尝试访问 SimpUserRegistry 它都是空的。

这个问题可能是什么原因造成的?

编辑:

正在显示 websocket 配置

@Configuration
@EnableWebSocket
@Controller
@Slf4j
public class WebSocketConfig implements WebSocketConfigurer {
    
    @Autowired
    EventTextHandler2 handler;
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        log.info("Registering websocket handler SocketTextHandler");
        registry.addHandler(handler, "/event").setHandshakeHandler(new CustomHandshakeHandlerTwo());
    }
}

SimpUserRegistry 是 Spring WebSocket 的“基础结构 bean”registered/provided,您不应该直接实例化它。

您的 WebSocket Spring 配置正确吗?

  1. 确保您的应用程序配置正确(即正在扫描您的配置 class)。

SimpUserRegistryspring-messaging 依赖项导入:确保您的配置 class 带有 @EnableWebSocketMessageBroker.

注释

官方文档:https://docs.spring.io/spring-framework/docs/5.3.6/reference/html/web.html#websocket-stomp-enable

  1. 要在 Redis 中支持连接的用户,您可能需要创建一个新的 SimpUserRegistry 实现:
public class RedisSimpUserRegistry implements SimpUserRegistry, SmartApplicationListener {

  private final RedisTemplate redisTemplate;

  public RedisSimpUserRegistry(RedisTemplate redisTemplate) {
    this.redisTemplate = redisTemplate;
  }

  [...]

  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    // Maintain Redis collection on event type
    // ie. SessionConnectedEvent / SessionDisconnectEvent
  }
  [...]
}

PS:您的配置 class 上的 @Controller 注释不是必需的,除非您在其中定义了端点。

在有新评论后编辑:

您可以查看 DefaultSimpUserRegistry 实现以了解如何执行此操作。

要拦截应用程序事件,您必须实现 ApplicationListener 接口(在本例中为 SmartApplicationListener)。 supportsEventType 方法对于定义要拦截的事件类型很重要:

  @Override
  public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    return AbstractSubProtocolEvent.class.isAssignableFrom(eventType);
  }

AbstractSubProtocolEvent 有多个实现。最重要的是 SessionConnectEvent, SessionDisconnectEvent.

拦截(参见 onApplicationEvent 方法)这些事件类型将允许您的实现在 Redis 缓存中保持所需的状态。然后您可以存储用户(id 等)。