首页 文章

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

提问于
浏览
11

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

3 回答

  • 6

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

    否则,请进行预检请求 . 使用引用来源,使用引用来源作为覆盖引用来源,使用OPTIONS方法设置块cookie标记,并使用以下附加约束来获取来自源源的请求URL:包括Access-Control-Request-Method标头作为头字段值的请求方法(即使这是一个简单的方法) . 如果作者请求标头不为空,则包含带有 Headers 字段值的Access-Control-Request-Headers标头,以字典顺序排列作者请求标头的 Headers 字段名称的逗号分隔列表,每个 Headers 转换为ASCII小写(即使是一个或更多是一个简单的 Headers ) . 排除作者请求标头 . 排除用户凭据 . 排除请求实体主体 .

    您必须允许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

    1. CORS Spring Framework为CORS提供了一流的支持 . 必须在Spring Security之前处理CORS,因为飞行前请求不包含任何cookie(即JSESSIONID) . 如果请求不包含任何cookie并且Spring Security是第一个,则该请求将确定用户未经过身份验证(因为请求中没有cookie)并拒绝它 . 确保首先处理CORS的最简单方法是使用CorsFilter . 用户可以通过使用以下内容提供CorsConfigurationSource来将CorsFilter与Spring Security集成:@EnableWebSecurity
      公共类WebSecurityConfig扩展WebSecurityConfigurerAdapter {

    @覆盖
    protected void configure(HttpSecurity http)抛出Exception {
    HTTP
    //默认使用名为corsConfigurationSource的Bean
    .cors()和()
    ...
    }

    @ beans
    CorsConfigurationSource corsConfigurationSource(){
    CorsConfiguration配置=新CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList( “https://example.com”));
    configuration.setAllowedMethods(Arrays.asList( “GET”, “POST”));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration(“/ **”,配置);
    返回来源;
    }
    }

  • 0

    从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

  • 9

    在我的情况下,我启用了启用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 是关键!

    https://github.com/spring-projects/spring-security-oauth/issues/938

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

相关问题