【问题标题】:Spring Boot - CORS filter works for GET, but not for other HTTP VerbsSpring Boot - CORS 过滤器适用于 GET,但不适用于其他 HTTP 动词
【发布时间】:2021-04-07 09:37:46
【问题描述】:

我正在使用带有 Angular 9 前端的 Spring Boot 2.2.5 应用程序。

我一直在尝试在 Spring Boot 后端配置一个 CORS 过滤器,以允许任何来源的任何请求的任何标头。

根据我的研究,我目前在我的主要 Application.java 文件中实现的内容应该可以工作:

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("DELETE");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

但是,我所经历的是,这只允许我从前端到后端的控制器执行GET 调用。对POSTPUT 的任何其他调用都会失败并出现以下错误:

Access to XMLHttpRequest at 'http://localhost:8080/spring-boot-starter-seed/default-theme/save/cyan' from origin 'http://localhost:8083' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我知道我走在了正确的轨道上,因为如果我删除了我实现的@Bean,那么从前端到后端的所有调用都会由于该错误而失败。但是在实现该 Bean 时,由于某种原因,它仅适用于 GET 请求。

有什么我遗漏的吗?

***** 更新 *****

我不知道这是否会有所帮助,但是,我正在使用 Azure AD 对此应用程序进行身份验证。我有一个看起来像这样的WebSecurityConfig

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

    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
        grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/actuator/**", "/heartbeat/**", "/register", "/unregister").permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(this.jwtAuthenticationConverter());
    }
}

在我之前的帖子中,我说过 GET 请求有效,但这似乎有些错误。

GET /heartbeat 有效。不过……

GET /default-theme 不起作用并失败并出现同样的 No Access-Control-Allow-Origin 错误。

这两个Controller路径的唯一区别是/default-theme不包含在排除的antMatchers中,它受到@PreAuthorize(value = "hasRole('ROLE_access')")的保护

【问题讨论】:

    标签: java angular spring spring-boot cors


    【解决方案1】:

    我认为这里的问题是由于调度程序servlet的过滤器:

    试试这个类来实现一个过滤器:

    public class CORSFilter extends GenericFilterBean implements Filter {
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chaine)
                throws IOException, ServletException {
            HttpServletResponse httpResponse = (HttpServletResponse)response;
            httpResponse.setHeader("Access-Control-Allow-Origin", "*");
            httpResponse.setHeader("Access-Control-Allow-Methods", "*");
            httpResponse.setHeader("Access-Control-Allow-Headers", "*");
            httpResponse.setHeader("Access-Control-Allow-Credentials", "false");
            httpResponse.setHeader("Access-Control-Max-Age", "3600");
            System.out.println("****************** CORS Configuration Completed *******************");
            chaine.doFilter(request, response);
        }
    
    }
    

    然后将 bean 注入您的主应用程序类或任何地方:

    @Bean
        public FilterRegistrationBean crosFilterRegistration(){
            FilterRegistrationBean registrationBean = new FilterRegistrationBean(new CORSFilter());
            registrationBean.setName("CORS Filter");
            registrationBean.addUrlPatterns("/*");
            registrationBean.setOrder(1);
            return registrationBean;
        }
    

    希望这会有所帮助

    【讨论】:

    • Amanoun,我尝试了您提供的内容,但结果相同。我已经用更多信息更新了我的帖子。
    【解决方案2】:

    因此,事实证明,我对原始帖子的更新是正确的,假设 Spring Security 和我的 WebSecurityConfig 是原因的一部分。

    我在here的答案中找到了真正的解决方案。

    我需要先更新我的HttpSecurity 配置以包含.cors()

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .authorizeRequests()
                .antMatchers("/actuator/**", "/heartbeat", "/register", "/unregister").permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(this.jwtAuthenticationConverter());
    }
    

    完成此操作后,所有其他 CORS 配置都是不必要的,可以从我的应用程序中删除。只需将@CrossOrigin 注解添加到任何相关控制器即可。

    有了这个,调用我的 GET /default-theme 控制器,受 @PreAuthorize(value = "hasRole('ROLE_access')") 保护,摆脱了 No Access-Control-Allow-Origin 错误,并导致了我预期的错误,即 401 响应。

    所有这一切的根本原因是因为我的任务是将此应用程序从 LDAP 身份验证迁移到 Azure AD 身份验证。

    希望这对将来的某人有所帮助。

    【讨论】:

      【解决方案3】:

      WebSecurityConfig 类中,您需要配置cors,如下所示

      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http
           ...
           .and()
           .cors().configurationSource(corsConfigurationSource())
           .and()
           ...
      }
      
      @Bean
          public CorsConfigurationSource corsConfigurationSource() {
              CorsConfiguration configuration = new CorsConfiguration();
              configuration.setAllowedOrigins(Arrays.asList(
                      "list of domains here"
                      )
              );
              configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT", "OPTIONS"));
              configuration.setAllowCredentials(true);
              configuration.setAllowedHeaders(
                      Arrays.asList(
                              "Access-Control-Allow-Headers",
                              "Access-Control-Allow-Origin",
                              "Access-Control-Request-Method",
                              "Access-Control-Request-Headers",
                              "Origin", "Cache-Control",
                              "Content-Type",
                              "Authorization"));
              UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
              source.registerCorsConfiguration("/**", configuration);
              return source;
          }
      
      

      【讨论】:

        猜你喜欢
        • 2018-03-09
        • 1970-01-01
        • 2015-01-04
        • 2017-01-25
        • 2018-02-23
        • 2015-09-06
        • 2020-08-05
        • 1970-01-01
        • 2018-11-12
        相关资源
        最近更新 更多