首页 > 解决方案 > SimpUserRegistry 不包含任何会话对象

问题描述

我是 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.


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


@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());
    }
}

标签: javaspring-bootwebsocket

解决方案


SimpUserRegistry是 Spring WebSocket 注册/提供的“基础设施 bean”,你不应该直接实例化它。

您的 WebSocket Spring 配置是否正确?

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

SimpUserRegistryspring-messaging依赖项导入:确保您的配置类使用@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:@Controller除非您在其中定义了端点,否则不需要对配置类进行注释。

新评论后编辑:

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

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

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

AbstractSubProtocolEvent多种实现。最重要的是SessionConnectEventSessionDisconnectEvent

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


推荐阅读