CORS 问题 - 请求的资源上不存在“Access-Control-Allow-Origin”标头

新手上路,请多包涵

我创建了两个 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 服务器进行部署。

原文由 JavaDeveloper 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 725
2 个回答

CORS 的预检请求使用 HTTP OPTIONS 没有凭据,请参阅 跨源资源共享

否则,进行 预检请求。使用 referrer 源作为覆盖 referrer 源,使用方法 OPTIONS 和以下附加约束从 origin source origin 获取请求 URL:

  • 包括一个 Access-Control-Request-Method 标头,并将请求方法作为标头字段值(即使这是一个简单的方法)。
  • 如果作者请求标头不为空,则包含一个 Access-Control-Request-Headers 标头,标头字段值是作者请求标头中按字典顺序排列的标头字段名称的逗号分隔列表,每个都转换为 ASCII 小写字母(即使是一个或更多是一个简单的标题)。
  • 排除作者请求标头。
  • 排除用户凭据。
  • 排除请求实体主体。

您必须允许匿名访问 HTTP OPTIONS

春季安全 3

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

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

你仍然需要你的 CORS 配置(可能有一些额外的值):

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

春季安全 4

从 Spring Security 4.2.0 开始,您可以使用内置支持,请参阅 Spring Security Reference

19.CORS

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

确保首先处理 CORS 的最简单方法是使用 CorsFilter 。用户可以通过使用以下命令提供 CorsConfigurationSourceCorsFilter 与 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;
  }
}

原文由 dur 发布,翻译遵循 CC BY-SA 4.0 许可协议

从 Spring Security 4.1 开始,这是使 Spring Security 支持 CORS 的正确方法(在 Spring Boot 1.41.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

原文由 Hendy Irawan 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题