在Spring中使用STOMP和WebSocket向特定用户发送消息时检查身份验证

vde*_*ris 8 spring stomp websocket spring-messaging

我正在开发一个实时通知系统弹簧4使用内置的Message Broker中,和蹬过的WebSocket.

我希望能够根据用户名向特定用户发送消息.为了实现这个目标,我正在使用类的convertAndSendToUser方法org.springframework.messaging.simp.SimpMessagingTemplate,如下所示:

private final MessagingTemplate messagingTemplate;

@Autowired
public LRTStatusListener(SimpMessagingTemplate messagingTemplate) {
    this.messagingTemplate = messagingTemplate;
}


@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
    messagingTemplate
        .convertAndSendToUser(principal.getName(), "/horray", "Horray, " + principal.getName() + "!");
}
Run Code Online (Sandbox Code Playgroud)

作为配置:

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notifications").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic", "/queue", "/user");
    }

}
Run Code Online (Sandbox Code Playgroud)

客户端(通过JavaScript),我应该通过指定用户名来订阅一个频道(根据另一个非常类似的问题:在Spring Websocket上向特定用户发送消息).

stompClient.subscribe('/user/' + username + '/horray, ...) 
Run Code Online (Sandbox Code Playgroud)

这最后一点听起来很奇怪......

假设我在我的webapp上以w.white身份登录,通过订阅:

stompClient.subscribe('/user/w.white/horray, ...)
Run Code Online (Sandbox Code Playgroud)

...我将能够看到发送给w.white的消息,这很棒......但订阅:

stompClient.subscribe('/user/j.pinkman/horray, ...)
Run Code Online (Sandbox Code Playgroud)

...我也可以看到发送给j.pinkman的消息,但是我当前记录为w.white.

这是克服这个问题的一种方法吗?


更新

下面是关于WebSocket连接的日志:

Opening Web Socket... 
Web Socket Opened... 
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000

<<< CONNECTED
user-name:w.white
heart-beat:0,0
version:1.1

connected to server undefined
Connected: CONNECTED
version:1.1
heart-beat:0,0
user-name:w.white

>>> SUBSCRIBE
id:sub-0
destination:/topic/lrt

>>> SUBSCRIBE
id:sub-1
destination:/user/lrt
Run Code Online (Sandbox Code Playgroud)

vde*_*ris 22

我找到了解决方案.

首先,重要的是要知道该/user通道已经由Spring STOMP管理,顺便说一下,不需要注册.

所以:

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic", "/queue");
}
Run Code Online (Sandbox Code Playgroud)

然后,我将目标通道设置为/queue/horray:

@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
    messagingTemplate
        .convertAndSendToUser(principal.getName(), "/queue/horray", "Horray, " + principal.getName() + "!");
}
Run Code Online (Sandbox Code Playgroud)

最后,在客户端:

stompClient.subscribe('/user/queue/horray', '...');
Run Code Online (Sandbox Code Playgroud)

现在,它工作正常!根据Principal安全上下文提取的消息,消息仅发送给指定的收件人.

  • 你好,@ vdenotaris.我注意到你发布消息的预定方法:@Scheduled(fixedDelay = 5000)public void sendMessages(Principal principal)messagingTemplate .convertAndSendToUser(principal.getName(),"/ queue/horray","Horray,"+ principal.getName( )+"!"); Spring计划的方法不适用于参数.如何在预定方法中获取Principal?提前致谢! (3认同)
  • 恭喜您解决方案。您是否知道使用@SendToUser注释是否会有类似的版本? (2认同)
  • 任何使用@Scheduled注释的方法都不能接受任何参数.@Scheduled(fixedDelay = 5000)public void sendMessages(Principal principal){}这不起作用. (2认同)

小智 7

由于我的应用程序上的用户未经过身份验证,因此我只使用会话ID来区分各种主题

在服务器上:

template.convertAndSend("/topic/warnings/" + sessionId, ...)
Run Code Online (Sandbox Code Playgroud)

客户端非常简单

stompClient.subscribe('/topic/warnings/${pageContext.session.id}', ...
Run Code Online (Sandbox Code Playgroud)

也许不是最干净的方式,但它的工作原理,没有身份验证,我无法使用/用户通道