CORS问题 - 请求的资源上没有“Access-Control-Allow-Origin”标头

时间:2017-02-03 03:12:37

标签: jquery spring tomcat spring-security cors

我创建了两个Web应用程序 - 客户端和服务应用程序。
当客户端和服务应用程序部署在同一个Tomcat实例中时,它们之间的交互正常。 但是当应用程序部署到单独的Tomcat实例(不同的机器)时,我在发送服务应用程序的请求时会收到以下错误。

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 401

我的客户端应用程序使用JQuery,HTML5和Bootstrap。

AJAX调用如下所示进行服务:

var auth = "Basic " + btoa({usname} + ":" + {password});
var service_url = {serviceAppDomainName}/services;

if($("#registrationForm").valid()){
    var formData = JSON.stringify(getFormData(registrationForm));
    $.ajax({
        url: service_url+action,
        dataType: 'json',
        async: false,
        type: 'POST',
        headers:{
            "Authorization":auth
        },
        contentType: 'application/json',
        data: formData,
        success: function(data){
            //success code
        },
        error: function( jqXhr, textStatus, errorThrown ){
            alert( errorThrown );
        });
}

我的服务应用程序使用Spring MVC,Spring Data JPA和Spring Security。

我已加入CorsConfiguration课程,如下所示:

CORSConfig.java

@Configuration
@EnableWebMvc
public class CORSConfig extends WebMvcConfigurerAdapter  {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("*");
    }
}

SecurityConfig.java

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@ComponentScan(basePackages = "com.services", scopedProxy = ScopedProxyMode.INTERFACES)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("authenticationService")
    private UserDetailsService userDetailsService;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().fullyAuthenticated();
        http.httpBasic();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();
    }

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

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }
}

Spring Security依赖项:

 <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.2.3.RELEASE</version>
</dependency>
<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.2.3.RELEASE</version>
</dependency>

我正在使用 Apache Tomcat 服务器进行部署。

8 个答案:

答案 0 :(得分:11)

CORS的预检请求使用没有凭据的HTTP OPTIONS,请参阅Cross-Origin Resource Sharing

  

否则,请执行预检请求。使用引用来源作为覆盖引用来源,使用OPTIONS方法设置手动重定向标记和块cookie标记,并使用以下附加约束,从原始来源获取请求URL:

     
      
  • 在请求方法中包含一个Access-Control-Request-Method标头作为标题字段值(即使这是一个简单的方法)。
  •   
  • 如果作者请求标头不为空,则包含带有标题字段值的Access-Control-Request-Headers标头,以字典顺序排列作者请求标头中的标题字段名称的逗号分隔列表,每个标题转换为ASCII小写(甚至当一个或多个是一个简单的标题时。)
  •   
  • 排除作者请求标题。
  •   
  • 排除用户凭据。
  •   
  • 排除请求实体正文。
  •   

您必须允许HTTP OPTIONS的匿名访问。

您修改后的(和简化的)代码:

@Override
protected void configure(HttpSecurity http) throws Exception {
   http
       .authorizeRequests()
           .andMatchers(HttpMethod.OPTIONS, "/**").permitAll()
           .antMatchers("/login").permitAll()
           .anyRequest().fullyAuthenticated()
           .and()
       .httpBasic()
           .and()
       .sessionManagement()
           .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
           .and()
       .csrf().disable();
}

自Spring Security 4.2.0起,您可以使用内置支持,请参阅Spring Security Reference

  

<强> 19。 CORS

     

Spring Framework为CORS提供了一流的支持。必须在Spring Security之前处理CORS,因为飞行前请求不包含任何cookie(即JSESSIONID)。如果请求不包含任何cookie并且Spring Security是第一个,则该请求将确定用户未经过身份验证(因为请求中没有cookie)并拒绝它。

     

确保首先处理CORS的最简单方法是使用CorsFilter。用户可以通过使用以下内容提供CorsFilter来将CorsConfigurationSource与Spring Security集成:

     
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http
          // by default uses a Bean by the name of corsConfigurationSource
          .cors().and()
          ...
  }

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
      CorsConfiguration configuration = new CorsConfiguration();
      configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
      configuration.setAllowedMethods(Arrays.asList("GET","POST"));
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", configuration);
      return source;
  }
}

答案 1 :(得分:8)

从Spring Security 4.1开始,这是使Spring Security支持CORS的正确方法(在Spring Boot 1.4 / 1.5中也需要):

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    }
}

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.csrf().disable();
        http.cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

执行以下任何操作,这是尝试解决问题的错误方法:

  • http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
  • web.ignoring().antMatchers(HttpMethod.OPTIONS);

参考:http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

答案 2 :(得分:1)

由于这些发布的示例都没有帮助我,因此我是根据自己的知识来做事情的。 通常,最复杂的错误总是发生在我身上。因此,这就是我处理此错误的方式。

在这种方法中:

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration cors = new CorsConfiguration();
    cors.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "HEAD", "DELETE"));
    UrlBasedCorsConfigurationSource source = new
            UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
    return source;
}

默认情况下,CorsConfiguration允许以下方法:POST,HEAD,GET,因此,PUT,DELETE将不起作用!我要做的是创建新的CorsConfiguration实例并设置允许的方法:

cors.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "HEAD", "DELETE"));

所以现在我的方法如下:

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration cors = new CorsConfiguration();
        cors.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "HEAD", "DELETE"));
        UrlBasedCorsConfigurationSource source = new
                UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", cors.applyPermitDefaultValues());
        return source;
    }

,它就像魅力。希望对您有所帮助。当然,所有其他配置都是由spring.io文档进行的

答案 3 :(得分:0)

在我的情况下,我启用了资源服务器并启用了OAuth安全性,并且上述任何解决方案都无效。经过一些调试和谷歌搜索后想出了原因。

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

基本上在这个例子中Ordered.HIGHEST_PRECEDENCE是关键!

{{3}}

各种pom依赖项会添加不同类型的过滤器,因此我们可能会遇到基于订单的问题。

答案 4 :(得分:0)

这适用于:spring-boot-starter-parent 2.2.6.RELEASE

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*").allowedMethods("*");
    }
}

将“ *”更改为产品中有意义的内容

答案 5 :(得分:0)

在主应用程序中添加以下配置。它在 spring boot应用程序2.3.1

中起作用
JavaRDD<Integer> mappartRdd = DF.repartition(3).javaRDD().mapPartitions(it->  Arrays.asList(JavaConversions.asScalaIterator(it).length()).iterator());

  StructType schema = new StructType()
                .add(new StructField("value", DataTypes.IntegerType, true, Metadata.empty()));
        Dataset<Row> df = spark.createDataFrame(mappartRdd.map(RowFactory::create), schema);
        df.show(false);
        df.printSchema();

        /**
         * +-----+
         * |value|
         * +-----+
         * |6    |
         * |8    |
         * |6    |
         * +-----+
         *
         * root
         *  |-- value: integer (nullable = true)
         */

参考来源:https://spring.io/guides/gs/rest-service-cors/

答案 6 :(得分:0)

尝试一下:

editorTheme

答案 7 :(得分:0)

在主应用程序中添加以下配置。它在 spring boot 应用程序 2.3.1

中对我有用
package com.example.restservicecors;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootApplication
public class RestServiceCorsApplication {

    public static void main(String[] args) {
        SpringApplication.run(RestServiceCorsApplication.class, args);
    }

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*").allowedMethods("*");
            }
        };
    }

}

参考来源https://spring.io/guides/gs/rest-service-cors/