Reputation: 835
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());
}
}
Upvotes: 2
Views: 1857
Reputation: 1289
SimpUserRegistry
is an "infrastructure bean" registered/provided by Spring WebSocket, you should not instantiate it directly.
Is your WebSocket Spring configuration correct?
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
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.).
Upvotes: 3