【问题标题】:Spring WebSockets with Spring Security ChannelInterceptor.presend function not being called on WebStomp.connect没有在 WebStomp.connect 上调用带有 Spring Security ChannelInterceptor.presend 函数的 Spring WebSockets
【发布时间】:2020-06-17 08:15:03
【问题描述】:

我正在使用 Spring Boot 2.1.8 并尝试实现具有 OAuth2 安全性的 websocket 微服务。我试过查看 Stackoverflow 上的其他类似问题。我的 ChannelInterceptor.presend 没有在 ws Connect 上触发时遇到问题。我希望能够在查询参数中从 OAuth2 JWT 授权用户。

我正在使用 wscat 通过命令测试我的服务

$ wscat -c ws://177.15.32.34:8080/collaboration?access_token=xxx.yyy.zzz

它将正常连接,并且在 websocket 关闭之前永远不会调用 ChannelInterceptor.presend,然后捕获 WebStomp.DISCONNECT 消息。

代码如下。我感谢您提供的任何见解或方向。

@SpringBootApplication
public class MyApplication {

  public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
  }
}
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
@Component
public class AuthChannelInterceptor implements ChannelInterceptor {

  @Override
  public Message<?> preSend(Message<?> message, MessageChannel channel) {

    final StompHeaderAccessor accessor =
        MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

    if (StompCommand.CONNECT.equals(accessor.getCommand())) {
      System.out.println("preSend called");
    }
    return message;
  }
}
@Configuration
@EnableWebSocketMessageBroker
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

  @Value("${stomp.endPoint}")
  private String stompEndpoint;

  @Override
  public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.interceptors(new AuthChannelInterceptor());
  }

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

  @Override
  public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    stompEndpointRegistry
        .addEndpoint("collaboration")
        .setAllowedOrigins("*");
  }

  @Bean
  public CorsFilter corsFilter() {

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true); // you USUALLY want this
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("OPTIONS");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
  }
}
@Configuration
@EnableWebSecurity(debug = true)
@Order(PriorityOrdered.HIGHEST_PRECEDENCE + 500)
public class ResourceServerWebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
    resolver.setAllowUriQueryParameter(true);

    http.sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
        .antMatchers(HttpMethod.GET, "/collaboration")
        .permitAll();
  }
}
@Configuration
public class WebSocketSecurityConfigurer extends AbstractSecurityWebSocketMessageBrokerConfigurer {

  @Override
  protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {

    messages.simpTypeMatchers(CONNECT, UNSUBSCRIBE, DISCONNECT, HEARTBEAT).permitAll()
                .simpDestMatchers("/**")
                .authenticated();


  }

  @Override
  protected boolean sameOriginDisabled() {
    return true;
  }
}

【问题讨论】:

    标签: spring spring-boot spring-security websocket


    【解决方案1】:

    我仍然无法让 ChannelInterceptor 正常工作以验证 websocket。我最终做的是重用 BearerTokenAuthenticationFilter ,但将其配置为将令牌作为查询参数处理。在我的WebsecurityConfigurerAdapter 中,我创建了以下 bean,然后将它们插入到安全过滤器链中,如下所示。

    @EnableWebSecurity
    @Configuration
    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
      @Bean
      public JwtDecoder jwtDecoder() {
        NimbusJwtDecoderJwkSupport jwtDecoder =
            (NimbusJwtDecoderJwkSupport) JwtDecoders.fromOidcIssuerLocation(issuerUri);
    
        return jwtDecoder;
      }
    
      @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
      public AuthenticationManager myAuthenticationManager() {
        //copied from OAuth2ResourceServerSecurityConfiguration
        JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(jwtDecoder());
        authenticationProvider.setJwtAuthenticationConverter(new JwtAuthenticationConverter());
        return authenticationProvider::authenticate;
      }
    
      @Bean("DefaultBearerTokenResolver")
      public DefaultBearerTokenResolver getDefaultBearerTokenResolver() {
        DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver();
        defaultBearerTokenResolver.setAllowUriQueryParameter(true);
        return defaultBearerTokenResolver;
      }
    
      @Bean("BearerTokenAuthenticationFilter")
      public BearerTokenAuthenticationFilter getBearerTokenAuthFilter() {
        AuthenticationManager authenticationManager = myAuthenticationManager();
        BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(authenticationManager);
        filter.setBearerTokenResolver(getDefaultBearerTokenResolver());
    
        AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();
        filter.setAuthenticationEntryPoint(authenticationEntryPoint);
    
        return filter;
      }
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
    
        http
                .anonymous().disable()
                .logout().disable()
                .csrf().disable()
                .formLogin().disable()
                .addFilterAfter(getBearerTokenAuthFilter()
                        , SecurityContextHolderAwareRequestFilter.class )
                .authorizeRequests()
            .anyRequest()
            .authenticated();
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-24
      • 2013-03-01
      • 2018-12-10
      • 2019-01-02
      • 2012-06-15
      • 1970-01-01
      • 2011-09-16
      • 2016-08-30
      • 2012-07-27
      相关资源
      最近更新 更多