Spring Security 和 Websocket 的 CORS 问题

Posted

技术标签:

【中文标题】Spring Security 和 Websocket 的 CORS 问题【英文标题】:CORS problems with Spring Security and Websocket 【发布时间】:2019-06-11 18:24:08 【问题描述】:

我正在开发一个基于 Spring 后端的 Ionic 应用程序。 我使用 JWT 身份验证实现了 Spring Security。我的应用程序将有一个聊天室,用户可以在其中私下或公开聊天。所以,我正在实现一个 WebSocket 系统,以便实时获取所有更新。

这是我的安全配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private UserDetailsService userDetailsService;

    private AuthenticationManager authenticationManager;

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception 
        authenticationManagerBuilder
                .userDetailsService(this.userDetailsService)
                .passwordEncoder(passwordEncoder());
    

    @Bean
    public PasswordEncoder passwordEncoder() 
        return new BCryptPasswordEncoder();
    

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception 
        return new JwtAuthenticationTokenFilter();
    

   // configurazione Cors per poter consumare le api restful con richieste ajax
    @Bean
    CorsConfigurationSource corsConfigurationSource() 
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("*");
        configuration.setAllowedMethods(Arrays.asList("POST, PUT, GET, OPTIONS, DELETE"));
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    


    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception 
         httpSecurity
         .csrf().disable()
         .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
         .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
         .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().cors().and()
         .authorizeRequests()
         .antMatchers(
                 HttpMethod.GET,
                 "/",
                 "/*.html",
                 "/favicon.ico",
                 "/**/*.html",
                 "/**/*.css",
                 "/**/*.js",
                 "/image/**").permitAll()
         .antMatchers("/socket/**").permitAll()
         .antMatchers("/public/**").permitAll().and()
         .authorizeRequests().anyRequest().authenticated().and();

         httpSecurity.headers().cacheControl();
    

    @Bean
    public AuthenticationManager customAuthenticationManager() throws Exception 
        return authenticationManager();
    

这是我的 WebSocket 配置:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) 
        registry.addEndpoint("/socket")
                .setAllowedOrigins("*")
                .withSockJS();
    

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) 
        registry.setApplicationDestinationPrefixes("/chat")
                .enableSimpleBroker("/subscribe");
    

在这种情况下,我目前面临这个错误:

访问 XMLHttpRequest 在 'http://localhost:8080/SpringApp/socket/info?t=1547732425329' 来自 来源“http://localhost:8100”已被 CORS 策略阻止: 响应中“Access-Control-Allow-Origin”标头的值必须 当请求的凭据模式为时,不是通配符“*” '包括'。发起请求的凭证模式 XMLHttpRequest 由 withCredentials 属性控制。

每个调用都在工作(我完全被 jwt 授权)但是 WebSocket 不能工作。

因此,我尝试在我的安全配置类中简单地删除配置方法中的 .cors()。这导致我遇到一个相反的问题:

error in chrome

确实,现在 WebSocket 可以完美运行,但每次 api 调用都会给我 401。

解决此问题的正确方法是什么? 谢谢

【问题讨论】:

如果您找到了解决方案,请将其发布为答案。我也遇到了这个问题。 【参考方案1】:

对于复制和粘贴问题中的代码的任何人:以下行不正确:

configuration.setAllowedMethods(Arrays.asList("POST, PUT, GET, OPTIONS, DELETE"));

应该是:

configuration.setAllowedMethods(Arrays.asList("POST", "PUT", "GET", "OPTIONS", "DELETE"));

【讨论】:

【参考方案2】:

是的,当我在我的一个项目中处理相关问题时遇到了同样的错误。解决方案是我必须将 allowed-origin 标头值设置为我的应用程序的 URL。如果您发送凭据,则不允许使用通配符值 (*)。

【讨论】:

感谢您的回复。我该怎么做? 由于您使用的是 spring security CORS 的 Java 配置,因此您必须在属性文件中进行设置,最好在 tomcat 配置中进行设置(例如应用程序的 context.xm)并在应用程序启动时读取该配置.对于测试,您可以将其设置为 localhost,例如"localhost:8080" 我可以直接在上面看到的 WebSecurityConfig 类的 corsConfigurationSource() 方法中执行吗? 是的,你可以在那里设置。只需将 addAllowedOrigin() 中的“*”替换为您的应用程序 URL

以上是关于Spring Security 和 Websocket 的 CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security入门(3-4)Spring Security 异常处理异常传递和异常获取

Spring 框架 4.0 和 Spring security 3.2.4 上的 Spring Security SAML 扩展

org.springframework.security.oauth 和 org.codehaus.spring-security-oauth 有啥区别?

Spring Security入门(3-5)Spring Security 的鉴权 - 决策管理器和投票器

在使用 Oauth、SAML 和 spring-security 的多租户的情况下从 spring-security.xml 中获取错误

Spring 中的 spring-security-oauth2 与 spring-security-oauth2-core