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依赖项:
org.springframework.security spring-security-config 3.2.3.RELEASE org.springframework.security spring-security-web 3.2.3.RELEASE
我正在使用Apache Tomcat服务器进行部署。
CORS的预检请求使用没有凭据的HTTP OPTIONS
,请参阅跨源资源共享 :
否则,请进行预检请求 。 使用引用来源作为覆盖引用来源,使用方法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是第一个,则该请求将确定用户未经过身份validation(因为请求中没有cookie)并拒绝它。确保首先处理CORS的最简单方法是使用
CorsFilter
。 用户可以通过使用以下内容提供CorsConfigurationSource
来将CorsFilter
与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; } }
从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
在我的情况下,我启用了资源服务器并启用了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依赖项添加了不同类型的filter,因此我们可能会遇到基于订单的问题。