har*_*z89 13 java activemq-classic stomp spring-messaging spring-websocket
我使用Spring的STOMP而不是WebSocket实现,使用功能齐全的ActiveMQ代理.当用户SUBSCRIBE访问某个主题时,在成功订阅之前,他们必须通过一些权限逻辑.我正在使用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());
}
}
Run Code Online (Sandbox Code Playgroud)
WebSocketSecurityConfig.java:
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpSubscribeDestMatchers("/stomp/**").authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").authenticated()
.anyMessage().denyAll();
}
}
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
当没有足够权限的客户端尝试订阅受限制的主题时,他们实际上从未接收到来自主题的任何消息,但也不会通知被拒绝订阅的异常.相反,客户端返回一个ActiveMQ代理一无所知的死定订阅.(正常,充分许可的客户端与STOMP端点的交互和主题的工作方式与预期一致.)
在成功连接之后,我已经尝试订阅users/{subscribingUsername}/queue/errors并简单地users/queue/errors使用我的Java测试客户端,但到目前为止,我无法从提供给客户端的服务器获得有关订阅异常的错误消息.这显然不太理想,因为客户端从未被通知他们被拒绝访问.
你不能只从抛出异常MySubscriptionInterceptor的clientInboundChannel,因为最后一个是ExecutorSubscribableChannel,因此async从这些线程的任何异常都与任何再掷给调用者日志结束了- StompSubProtocolHandler.handleMessageFromClient.
但是你可以做的就是像这样clientOutboundChannel使用它:
StompHeaderAccessor headerAccessor = StompHeaderAccessor.create(StompCommand.ERROR);
headerAccessor.setMessage(error.getMessage());
clientOutboundChannel.send(MessageBuilder.createMessage(new byte[0], headerAccessor.getMessageHeaders()));
Run Code Online (Sandbox Code Playgroud)
另一个需要考虑的选项是注释映射:
@SubscribeMapping("/foo")
public void handleWithError() {
throw new IllegalArgumentException("Bad input");
}
@MessageExceptionHandler
@SendToUser("/queue/error")
public String handleException(IllegalArgumentException ex) {
return "Got error: " + ex.getMessage();
}
Run Code Online (Sandbox Code Playgroud)