使用 spring 发送用户特定的消息

Posted

技术标签:

【中文标题】使用 spring 发送用户特定的消息【英文标题】:Send User-specific message with spring 【发布时间】:2018-11-18 08:28:12 【问题描述】:

我有一个端点 (/create),它有一些逻辑,需要 3-4 分钟来处理,所以我使用 rabbitmq,一旦端点收到请求,它就会获取正文并将消息发布到监听器 rabbitmq监听消息并处理请求现在我想通知用户他的请求已成功处理。

websocket 是满足此要求的正确选择吗 还有其他更好的方法可以实现我的目标吗?

所以我继续使用 websocket,因为我使用的是基于 oauth 的身份验证,我无法让 web-socket 工作

这是我写的代码:

SocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer 

  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) 
    config.enableSimpleBroker("/topic","/secured/queue");
    //config.setApplicationDestinationPrefixes("/app");
    //config.setUserDestinationPrefix("/secured/user");
  

  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) 
    registry.addEndpoint("/secured/messagereg").setAllowedOrigins("*").withSockJS();
  

SocketHandler.java

@Configuration
public class SocketHandler extends AbstractSecurityWebSocketMessageBrokerConfigurer 

  @Override
  protected boolean sameOriginDisabled() 
    return true;
  

  @Override
  protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) 
    messages
        .simpDestMatchers("/secured/**", "/secured/**/**").authenticated()
        .anyMessage().authenticated();
  

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Profile("!test")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

  @Autowired
  private Auth0PropertyConfig config;

  @Override
  protected void configure(HttpSecurity http) throws Exception 
    JwtWebSecurityConfigurer
        .forRS256(config.getAudience(), config.getIssuer())
        .configure(http)
        .cors()
        .and()
        .csrf().disable()
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    ;
  

客户代码

 const socket = new SockJs("/secured/messagereg/?access_token="+token);
    this.setState( clientRef: Stomp.over(socket) , () =>
      this.state.clientRef.connect(,
        frame => 
          this.setState( connection: true );
          this.state.clientRef.subscribe("/user/secured/queue/reply", message => 
            console.log("asd received ----------" + message.body);
            this.setState(prevs => (
              message: [...prevs.message, message]
            ));
          );
        ,
        error => 
          console.log("Stomp protocol error." + error);
        
      )
    );

我在连接到套接字时收到 401 未授权。

【问题讨论】:

【参考方案1】:

在我看来:推送消息模式(例如使用 STOMP)适合这种情况,但这最终取决于您的架构原则。您还可以轮询服务器以获取结果(使用 REST API),该结果既有优点(共享安全架构)也有缺点(客户端代码、流量和反应时间开销)。

答案:

为了让您的代码正常工作,我认为您需要在 SocketConfig.java 中再添加一种方法,该方法将挂钩到您的 OAUTH 过滤器(或您可能使用的任何方法)。

重要 - websocket 身份验证不会重用现有的 Spring Security 上下文。这就是为什么您需要再次实现身份验证的原因,例如在 SocketConfig 类中使用 WebSocketMessageBrokerConfigurer 的方法 configureClientInboundChannel

以下示例假设您之前已经获得了 OAUTH 令牌,并且它仅用于重新验证 websocket 连接。在StompHeaderAccessor(倒数第三行)中设置用户引用将使您的代码能够向正确的用户发送消息。

它还要求在消息头中设置 OAUTH 令牌,而不是您示例中的端点参数。我认为这对于 websocks 消息传递可能更安全,因为如果您使用 wss,消息本身会在协议级别加密。

@Autowired
private YourOauthService auth;

@Override
public void configureClientInboundChannel(ChannelRegistration registration) 
    registration.interceptors(new ChannelInterceptor() 
        @Override
        public Message<?> preSend(Message<?> message, MessageChannel channel) 
            StompHeaderAccessor accessor =
                    MessageHeaderAccessor.getAccessor(message,
                           StompHeaderAccessor.class);
            if (StompCommand.CONNECT.equals(accessor.getCommand())) 
                String token = accessor.removeNativeHeader("Authorization").get(0);
                Authentication user = auth.getAuthentication(token);

                accessor.setUser(user);
            
            return message;
        
    );

我在https://robertleggett.wordpress.com/2015/05/27/websockets-with-spring-spring-security/发现了一些更有趣的例子

【讨论】:

你能帮我做authenticationService吗实际上我正在使用oauth.com进行身份验证。 @AdibRajiwate 我建议您为此提出另一个问题,因为这是一个完全不同的话题。我看看能不能帮到你。同时,如果您对我的回答满意,请采纳。

以上是关于使用 spring 发送用户特定的消息的主要内容,如果未能解决你的问题,请参考以下文章

Spring引导Web套接字,无需向特定用户发送消息

如何通过spring websocket STOMP向特定订阅发送消息?

Spring使用Spring和AMQP发送接收消息(上)

如何使用 websockets 通过 Flask 向特定用户发送消息?

SignalR - 使用 (IUserIdProvider) *NEW 2.0.0* 向特定用户发送消息

如何使用 discord.js 从 discord bot 向特定用户发送消息