我正在使用Spring的STOMP over WebSocket实现,并配合一个功能齐全的ActiveMQ代理。当用户订阅主题时,他们必须通过某些权限逻辑才能成功订阅。我正在使用ChannelInterceptor来应用权限逻辑,如下所配置:
WebSocketConfig.java:
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp")
.setAllowedOrigins("*")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("relayhost.mydomain.com")
.setRelayPort(61613);
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new MySubscriptionInterceptor());
}
}
WebSocketSecurityConfig.java:
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpSubscribeDestMatchers("/stomp/**").authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").authenticated()
.anyMessage().denyAll();
}
}
MySubscriptionInterceptor.java:
public class MySubscriptionInterceptor extends ChannelInterceptorAdapter {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
Principal principal = headerAccessor.getUser();
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
checkPermissions(principal);
}
return message;
}
private void checkPermissions(Principal principal) {
// apply permissions logic
// throw Exception permissions not sufficient
}
}
当没有足够权限的客户端尝试订阅受限制的主题时,它们实际上从主题中根本没有接收到任何消息,但也没有收到拒绝他们的订阅的异常通知。相反,客户端会收到一个ActiveMQ代理不知道的无效订阅。(正常的、有适当权限的客户端与STOMP端点和主题的交互正常工作。)在成功连接后,我已经尝试使用我的Java测试客户端订阅
users/{subscribingUsername}/queue/errors
和普通的users/queue/errors
,但迄今为止我无法从服务器传递给客户端关于订阅异常的任何错误消息。这显然不太理想,因为客户端从未收到被拒绝访问的通知。
@SubscribeMapping
方法中抛出异常并由@MessageExceptionHandler
方法处理时,确实会向客户端的错误队列发送消息,但他们的订阅仍然转发到代理,并且客户端仍然从主题接收后续消息。 - hartz89@MessageExceptionHandler
直接使用send
将消息发送到clientOutboundChannel
。 - Artem Bilan