Spring 带有 STOMP 的 MVC Websockets - 针对特定通道进行身份验证
Spring MVC Websockets with STOMP - Authenticate against specific channels
AbstractWebSocketMessageBrokerConfigurer
(Spring Boot)有没有办法拦截用户注册到特定频道?
我在 registerStompEndpoints
中使用 HandshakeHandler 完成了基本身份验证:
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
HandshakeHandler handler = new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request,
WebSocketHandler wsHandler, Map<String, Object> attributes) {
Principal principal = request.getPrincipal();
if (principal == null) {
return () -> getPrincipal();
}
return principal;
}
};
registry.addEndpoint("/websocket")
.setHandshakeHandler(handler)
.setAllowedOrigins("*").withSockJS();
}
现在,如果该用户没有 'admin' 权限,我想阻止该用户注册到“/topic/admin/news”。我没有使用 Spring 安全性。我想在注册频道之前有一个拦截器。
作为替代方案,我想使用 SimpMessagingTemplate
仅从具有权限的频道向用户发送消息。有没有办法查看当前连接到我的 stomp-connection 的用户?
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new TopicSubscriptionInterceptor());
}
拦截器:
public class TopicSubscriptionInterceptor implements ChannelInterceptor {
private static Logger logger = org.slf4j.LoggerFactory.getLogger(TopicSubscriptionInterceptor.class);
@Override
public Message<?> postReceive(Message<?> message, MessageChannel chanenel) {
return message;
}
@Override
public void postSend(Message<?> message, MessageChannel chanel, boolean sent) {
}
@Override
public boolean preReceive(MessageChannel channel) {
return true;
}
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand()) && headerAccessor.getHeader("simpUser") !=null && headerAccessor.getHeader("simpUser") instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) headerAccessor.getHeader("simpUser");
if(!validateSubscription((User)userToken.getPrincipal(), headerAccessor.getDestination()))
{
throw new IllegalArgumentException("No permission for this topic");
}
}
return message;
}
private boolean validateSubscription(User principal, String topicDestination)
{
logger.debug("Validate subscription for {} to topic {}",principal.getUsername(),topicDestination);
//Validation logic coming here
return true;
}
}
AbstractWebSocketMessageBrokerConfigurer
(Spring Boot)有没有办法拦截用户注册到特定频道?
我在 registerStompEndpoints
中使用 HandshakeHandler 完成了基本身份验证:
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
HandshakeHandler handler = new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request,
WebSocketHandler wsHandler, Map<String, Object> attributes) {
Principal principal = request.getPrincipal();
if (principal == null) {
return () -> getPrincipal();
}
return principal;
}
};
registry.addEndpoint("/websocket")
.setHandshakeHandler(handler)
.setAllowedOrigins("*").withSockJS();
}
现在,如果该用户没有 'admin' 权限,我想阻止该用户注册到“/topic/admin/news”。我没有使用 Spring 安全性。我想在注册频道之前有一个拦截器。
作为替代方案,我想使用 SimpMessagingTemplate
仅从具有权限的频道向用户发送消息。有没有办法查看当前连接到我的 stomp-connection 的用户?
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new TopicSubscriptionInterceptor());
}
拦截器:
public class TopicSubscriptionInterceptor implements ChannelInterceptor {
private static Logger logger = org.slf4j.LoggerFactory.getLogger(TopicSubscriptionInterceptor.class);
@Override
public Message<?> postReceive(Message<?> message, MessageChannel chanenel) {
return message;
}
@Override
public void postSend(Message<?> message, MessageChannel chanel, boolean sent) {
}
@Override
public boolean preReceive(MessageChannel channel) {
return true;
}
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand()) && headerAccessor.getHeader("simpUser") !=null && headerAccessor.getHeader("simpUser") instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) headerAccessor.getHeader("simpUser");
if(!validateSubscription((User)userToken.getPrincipal(), headerAccessor.getDestination()))
{
throw new IllegalArgumentException("No permission for this topic");
}
}
return message;
}
private boolean validateSubscription(User principal, String topicDestination)
{
logger.debug("Validate subscription for {} to topic {}",principal.getUsername(),topicDestination);
//Validation logic coming here
return true;
}
}