SimpUserRegistry 不包含任何会话对象 [英] SimpUserRegistry doesnot contain any session objects

查看:47
本文介绍了SimpUserRegistry 不包含任何会话对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<预><代码>导入 java.security.Principal;公共类 StompPrincipal 实现 Principal {私人字符串名称;公共 StompPrincipal(字符串名称){this.name = 名称;}@覆盖公共字符串 getName() {返回名称;}}

处理程序

class CustomHandshakeHandlerTwo 扩展 DefaultHandshakeHandler {//用于存储主体的自定义类@覆盖受保护的主体确定用户(ServerHttpRequest 请求,WebSocketHandler wsHandler,映射<字符串,对象>属性){//生成以 UUID 为名称的主体返回新的 StompPrincipal(UUID.randomUUID().toString());}}

但正如许多问题所指定的那样this我'无法直接注入 SimpUserRegistry.

它抛出错误

<预><代码>字段 simpUserRegistry 需要一个无法找到的org.springframework.messaging.simp.user.SimpUserRegistry"类型的 bean.注入点有以下注释:- @org.springframework.beans.factory.annotation.Autowired(required=true)行动:考虑在您的配置中定义一个 'org.springframework.messaging.simp.user.SimpUserRegistry' 类型的 bean.

所以我创建了一个如下所示的配置类.

<预><代码>@配置公共类用户配置 {final private SimpUserRegistry userRegistry = new DefaultSimpUserRegistry();@豆@主要公共 SimpUserRegistry userRegistry() {返回用户注册表;}}

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

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

显示 websocket 配置

@Configuration@EnableWebSocket@控制器@Slf4j公共类 WebSocketConfig 实现 WebSocketConfigurer {@自动连线EventTextHandler2 处理程序;public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {log.info("注册 websocket 处理程序 SocketTextHandler");registry.addHandler(handler, "/event").setHandshakeHandler(new CustomHandshakeHandlerTwo());}}

解决方案

SimpUserRegistry 是一个基础架构 bean"由 Spring WebSocket 注册/提供,请勿直接实例化.

您的 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 实现了 SimpUserRegistry、SmartApplicationListener {私有最终RedisTemplate redisTemplate;公共RedisSimpUserRegistry(RedisTemplate redisTemplate){this.redisTemplate = redisTemplate;}[...]@覆盖公共无效 onApplicationEvent(ApplicationEvent 事件) {//维护事件类型的Redis集合//即.SessionConnectedEvent/SessionDisconnectEvent}[...]}

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

新评论后

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

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

 @Overridepublic boolean supportsEventType(Class eventType) {返回 AbstractSubProtocolEvent.class.isAssignableFrom(eventType);}

AbstractSubProtocolEvent 有多种实现.最重要的是SessionConnectEventSessionDisconnectEvent.

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

Iam new to Websockets. I have been trying to use SimpUserRegistry to find session object by Principal. I wrote a custom handshake handler to convert Anonymous users to authenticated users and Iam able to access the Principal name from Websocket session object.

The code for custom handshake handler is shown below


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

Handler

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

But as specified in many questions like this I'am not able to inject the SimpUserRegistry directly.

It throws error


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.


So I created a configuration class as shown below.


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

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

Now I can autowire and use it but everytime I try to acess the SimpUserRegistry it is empty.

What could be the cause of this problem?

EDIT:

Showing websocket config

@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 is an "infrastructure bean" registered/provided by Spring WebSocket, you should not instantiate it directly.

Is your WebSocket Spring configuration correct?

  1. Make sure your application is well configured (ie. your configuration class is being scanned).

SimpUserRegistry is imported by spring-messaging dependency: make sure your configuration class is annotated with @EnableWebSocketMessageBroker.

Official documentation: https://docs.spring.io/spring-framework/docs/5.3.6/reference/html/web.html#websocket-stomp-enable

  1. To back the connected users in Redis, you may want to create a new SimpUserRegistry implementation:

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: The @Controller annotation on your config class is not necessary unless you have an endpoint defined in it.

Edit after new comments:

You can see the DefaultSimpUserRegistry implementation to get an idea of how to do it.

To intercept an application event, you have to implement the ApplicationListener interface (in this case SmartApplicationListener). The supportsEventType method is important to define which event types you want to intercept:

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

The AbstractSubProtocolEvent have multiple implementations. The most important ones are SessionConnectEvent, SessionDisconnectEvent.

Intercepting (see onApplicationEvent method) these event types will allow your implementation to maintain the desired state in your Redis cache. You could then store users (ids, etc.).

这篇关于SimpUserRegistry 不包含任何会话对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆