Spring Boot - CORS 过滤器适用于 GET,但不适用于其他 HTTP 动词
Posted
技术标签:
【中文标题】Spring Boot - CORS 过滤器适用于 GET,但不适用于其他 HTTP 动词【英文标题】:Spring Boot - CORS filter works for GET, but not for other HTTP Verbs 【发布时间】: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
调用。对POST
或PUT
的任何其他调用都会失败并出现以下错误:
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')")
的保护
【问题讨论】:
【参考方案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;
【讨论】:
以上是关于Spring Boot - CORS 过滤器适用于 GET,但不适用于其他 HTTP 动词的主要内容,如果未能解决你的问题,请参考以下文章
Zuul Proxy CORS 头包含多个值,头重复两次 - Java Spring Boot CORS 过滤器配置