标签: spring-messaging

Spring @SubscribeMapping是否真的为客户订阅某个主题?

我正在使用Spring Websocket和STOMP,Simple Message Broker.在我的@Controller使用方法级别@SubscribeMapping,它应该将客户端订阅到主题,以便客户端之后将接收该主题的消息.假设客户订阅主题"聊天":

stompClient.subscribe('/app/chat', ...);

当客户订阅"/ app/chat "而不是"/ topic/chat"时,此订阅将转到使用以下方法映射的方法@SubscribeMapping:

@SubscribeMapping("/chat")
public List getChatInit() {
    return Chat.getUsers();
}
Run Code Online (Sandbox Code Playgroud)

这是Spring ref.说:

默认情况下,@ SubsscribeMapping方法的返回值作为消息直接发送回连接的客户端,并且不通过代理.这对于实现请求 - 回复消息交互很有用; 例如,在初始化应用程序UI时获取应用程序数据.

好的,这就是我想要的,但只是部分 !! 订阅后发送一些init-data,好吧.但订阅呢?在我看来,这里发生的事情只是一个请求 - 回复,就像一个服务.订阅只是消费.如果是这种情况,请澄清我.

  • 如果经纪人没有参与此活动,客户是否订阅了某些地方?
  • 如果以后我想向"聊天"下标者发送一些消息,客户会收到它吗?它似乎不是这样.
  • 谁真正实现了订阅?经纪人?或者其他人?

如果在这里客户端没有订阅任何地方,我想知道为什么我们称之为"订阅"; 因为客户端只收到一条消息而不是后续消息.

编辑:

为了确保订阅已经实现,我尝试的内容如下:

服务器端:

组态:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/hello").withSockJS();
    } …
Run Code Online (Sandbox Code Playgroud)

spring stomp messagebroker spring-messaging spring-websocket

35
推荐指数
4
解决办法
2万
查看次数

使用WebSockets进行Spring安全性 - 禁止使用403

我在Spring中实现了WebSocket.一切正常,但最近我决定实施Spring Security.

我的MessageBroker看起来像:

@Configuration
@EnableWebSocketMessageBroker
@Component("messageBroker")
public class MessageBroker implements WebSocketMessageBrokerConfigurer {

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

    @Override
    public void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        messageConverters.add(new MappingJackson2MessageConverter());
        return false;
    }

}
Run Code Online (Sandbox Code Playgroud)

我的JS客户端看起来很喜欢这个:

var socket = new SockJS('/server/graphs');
var client = Stomp.over(socket);

client.connect({}, function (frame) {
    client.subscribe("/data", function (message) {
        console.log('GET MESSAGE :' + message.body);
        var test = JSON.parse(message.body); …
Run Code Online (Sandbox Code Playgroud)

spring stomp spring-security spring-messaging spring-websocket

17
推荐指数
1
解决办法
3066
查看次数

无法自动装配.找不到SimpMessagingTemplate类型的bean

我基本上按照文档中提供的指南在Spring中配置Websockets.

我正在尝试从服务器向客户端发送消息,如 " 从任何地方发送消息 " 一节中所述

在示例之后,您可以自动装配名为SimpMessagingTemplate的类

@Controller
public class GreetingController {

    private SimpMessagingTemplate template;

    @Autowired
    public GreetingController(SimpMessagingTemplate template) {
        this.template = template;
    }

    @RequestMapping(value="/greetings", method=POST)
    public void greet(String greeting) {
        String text = "[" + getTimestamp() + "]:" + greeting;
        this.template.convertAndSend("/topic/greetings", text);
    }

}
Run Code Online (Sandbox Code Playgroud)

但是,我当前的项目找不到bean"SimpMessagingTemplate".(Intellij:'无法自动装配.没有找到SimpMessagingTemplate类型的bean'.

我在互联网上查了几个例子,但是我找不到如何让Spring创建一个SimpMessagingTemplate实例.我怎样才能自动装配它?

编辑:

我决定发送更多背景信息.这是我目前的websocket配置:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:websocket="http://www.springframework.org/schema/websocket"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/websocket
        http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">

        <!-- TODO properties to be read from a properties file -->
        <websocket:message-broker application-destination-prefix="/app">
            <websocket:stomp-endpoint path="/new_session" >
                <websocket:sockjs/>
            </websocket:stomp-endpoint>
            <websocket:simple-broker prefix="/topic"/>
        </websocket:message-broker> …
Run Code Online (Sandbox Code Playgroud)

java stomp javabeans autowired spring-messaging

16
推荐指数
3
解决办法
3万
查看次数

如何从Spring 4 stomp websocket方法获取/设置主体和会话属性

我正在使用Spring 4 websockets和stomp进行实验,我很难弄清楚如何在注释的消息处理方法中获取/设置当前用户和其他会话属性@MessageMapping.

该文件说,处理方法的消息可以采取委托作为参数,我发现主要是由春检索调用getUserPrincipal()在本机插座会话,然后与插座会话相关的,但我没有发现任何方式除了编写servlet过滤器并将原始请求包装回一个返回我的cookie中找到的主体的包装器之外,可以轻松地自定义此行为.

所以我的问题是:

  1. 如何在客户端连接时手动将主体设置为套接字会话(由于自定义cookie,我有这个信息,而且我不使用Spring安全性)?
  2. 如果1不可用,如何在客户端连接时向套接字会话添加其他属性?
  3. 如何从消息处理方法访问套接字会话及其属性?
  4. 有没有办法在连接时访问浏览器发送的登录名和密码.它们似乎被Spring完全忽略而且无法访问.

spring stomp websocket spring-messaging spring-websocket

15
推荐指数
2
解决办法
1万
查看次数

Spring Websockets @SendToUser没有登录?

我有一个带有websocket功能的简单弹簧应用程序,到目前为止一切正常.现在我想使用@SendToUser注释从我的服务器向特定客户端发送消息.这给了我错误"忽略消息,没有可用的主要信息".我知道我的服务器上没有任何登录信息,因此每个用户都是"匿名"且没有委托人(我现在不使用Spring安全性).但是每个用户都有一个session-id.是否有可能以某种方式使用会话ID来区分用户?我如何实现这一点,以便我的用户获得与session-id相对应的主体?

java spring spring-security spring-messaging spring-websocket

14
推荐指数
3
解决办法
9448
查看次数

如何使用Spring WebSocket向STOMP客户端发送ERROR消息?

我使用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 …
Run Code Online (Sandbox Code Playgroud)

java activemq-classic stomp spring-messaging spring-websocket

13
推荐指数
1
解决办法
6666
查看次数

Spring-Cloud-AWS 与 AWS-SDK-Java 2

我们的应用程序是基于 Spring-Boot 的。为了与 AWS SNS 和 SQS 集成,我们有以下几种选择:

  1. 使用 Spring-Cloud-AWS
  2. 使用 AWS-SDK-Java 2

我想知道使用其中之一是否有任何优势。

当我询问 AWS 人员时,他们告诉我 AWS SDK 会定期更新,并且与 SNS 和 SQS 集成并不困难。因此,无需与 Spring-Cloud-AWS 集成。

我尝试在 gitter 频道上搜索 Spring-Cloud,但找不到任何相关信息。文档确实表明我可以更新 AWS-SDK 版本。文档没有说明不直接使用 AWS-SDK 的任何令人信服的理由。

如果有人有一些见解,请分享。

amazon-web-services spring-messaging spring-cloud aws-sdk-java-2.0

9
推荐指数
1
解决办法
4491
查看次数

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

我正在开发一个实时通知系统弹簧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/' + …
Run Code Online (Sandbox Code Playgroud)

spring stomp websocket spring-messaging

8
推荐指数
2
解决办法
8105
查看次数

为什么SimpUserRegistry在EC2实例上无法正常工作

SimpUserRegistry用来获取在线用户数(带getUserCount()).它在我的本地机器上运行良好,但在AWS EC2实例(使用Amazon Linux和Ubuntu试用)上只有弹性IP且没有负载均衡器.

EC2上的问题是,某些用户在连接时从未添加到注册表中,因此我得到错误的结果.

我有会话监听器,为SessionConnectedEventSessionDisconnectEvent,在这里我使用SimpUserRegistry(自动装配Autowired)来获得用户的存在.如果重要的话,我也是SimpUserRegistry一个消息传递控制器.

以下是websocket消息代理配置:

@Order(Ordered.HIGHEST_PRECEDENCE + 99)
@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WebSocketMessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @NonNull
    private SecurityChannelInterceptor securityChannelInterceptor;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(1);
        threadPoolTaskScheduler.setThreadGroupName("cb-heartbeat-");
        threadPoolTaskScheduler.initialize();

        config.enableSimpleBroker("/queue/", "/topic/")
                .setTaskScheduler(threadPoolTaskScheduler)
                .setHeartbeatValue(new long[] {1000, 1000});

        config.setApplicationDestinationPrefixes("/app");
    }

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

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(securityChannelInterceptor);
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是上面配置类中使用的通道拦截器:

@Slf4j …
Run Code Online (Sandbox Code Playgroud)

java amazon-ec2 websocket spring-messaging spring-websocket

8
推荐指数
1
解决办法
671
查看次数

Spring安全websocket和HTTP身份验证/授权

总结 我想通过STOMP实现websocket通信.在第一次(HTTP请求)websocket握手时验证用户,并使用此Principal稍后授权websocket消息.

问题 系统在第一次尝试连接到websocket端点(HTTP握手的时间)时对客户端进行身份验证.我的Spring安全过滤器和身份验证提供程序完成其工作并正确验证客户端.在此之后,我可以检查客户端是否获得了角色,我的身份验证对象也存储在SecurityContext中.(此时已建立websocket连接,并且已丢弃HTTP协议.)但是,从第一个websocket通信我得到Authentication对象是Anonymous,因为SecurityContextHolder以某种方式被清除,因为SecurityContextChannelInterceptor清除它.

Spring文档声明如下:http://docs.spring.io/autorepo/docs/spring-security/current/reference/htmlsingle/#websocket-authentication

WebSockets重用与WebSocket连接时在HTTP请求中找到的相同身份验证信息.这意味着HttpServletRequest上的Principal将被移交给WebSockets.如果您使用的是Spring Security,则会自动覆盖HttpServletRequest上的Principal.

我非常简单的过滤器

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

    try {


        Authentication authResult =
                new CertAuthenticationToken(null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));

        authResult = getAuthenticationManager().authenticate(authResult);

        if (authResult.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authResult);
            LOGGER.info("Client was authenticated.");
        }
        chain.doFilter(request, response);

    } catch (AuthenticationException ae) {
        LOGGER.error("Client was not authenticated. {}", ae);
        SecurityContextHolder.clearContext();
        onUnsuccessfulAuthentication((HttpServletRequest) request, (HttpServletResponse) response, ae);
        throw ae;
    }
}
Run Code Online (Sandbox Code Playgroud)

我非常简单的认证提供商

 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        authentication.setAuthenticated(true);
        return …
Run Code Online (Sandbox Code Playgroud)

spring spring-security spring-boot spring-messaging spring-websocket

7
推荐指数
0
解决办法
5983
查看次数