英文:
Spring CORS Filter for Access-Control-Allow-Private-Network not working
问题
I have a webapp hosted on a public URL, trying to call a local webservice API (running on localhost)
我有一个托管在公共URL上的Web应用程序,试图调用本地运行的webservice API(运行在localhost上)
I am using Chrome to access the public website, this creates a CORS issue as described here
我正在使用Chrome访问公共网站,这会导致跨源资源共享(CORS)问题,如下所述
The solution stated in the above link is to either,
上述链接中提到的解决方法是要么:
-
Disable Private Network Access checks in Chrome (which works)
-
在Chrome中禁用私有网络访问检查(可行)
-
Set response header "Access-Control-Allow-Private-Network: true" (doesn't work)
-
设置响应头"Access-Control-Allow-Private-Network: true"(不起作用)
There is no Spring CORS support for the header "Access-Control-Allow-Private-Network" yet. So I have tried various ways to create a filter in my Spring Boot application, but to no avail. The filter never gets invoked and I encounter the CORS issue.
目前Spring还不支持"Access-Control-Allow-Private-Network"响应头的CORS。因此,我已经尝试了多种方法来在我的Spring Boot应用程序中创建过滤器,但都没有成功。过滤器从未被调用,我遇到了CORS问题。
Please point me in the right direction to fix this issue.
请指导我正确的方向来解决这个问题。
This is my filter class
这是我的过滤器类
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter invoked............");
final HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Private-Network", "true");
filterChain.doFilter(servletRequest, servletResponse);
}
}
This is my config class
这是我的配置类
@Configuration
public class MyConfig {
@Bean
public WebMvcConfigurer corsMappingConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
英文:
I have a webapp hosted on a public URL, trying to call a local webservice API (running on localhost)
I am using Chrome to access the public website, this creates a CORS issue as described here
https://developer.chrome.com/blog/private-network-access-preflight/
The solution stated in the above link is to either,
- Disable Private Network Access checks in Chrome (which works)
- Set response header "Access-Control-Allow-Private-Network: true" (doesnt work)
There is no Spring CORS support for the header "Access-Control-Allow-Private-Network" yet. So I have tried various ways to create a filter in my Spring Boot application, but to no avail. The filter never gets invoked and I encounter the CORS issue.
Please point me in the right direction to fix this issue.
This is my filter class
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter invoked............");
final HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Private-Network", "true");
filterChain.doFilter(servletRequest, servletResponse);
}
}
This is my config class
@Configuration
public class MyConfig {
@Bean
public WebMvcConfigurer corsMappingConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
答案1
得分: 1
这不完全是解释为什么你的代码不起作用的答案,但我刚刚创建了一种使用Spring实现的方法,可能对你有所帮助。我正在使用Spring Boot 2.7,因此包括了Spring 5.3。
它使用自定义的CorsProcessor
类来向响应添加相关的标头。
CustomCorsProcessor.java
:
public class CustomCorsProcessor extends DefaultCorsProcessor implements CorsProcessor {
private static final String ACCESS_CONTROL_REQUEST_PRIVATE_NETWORK = "Access-Control-Request-Private-Network";
private static final String ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK = "Access-Control-Allow-Private-Network";
@Override
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 允许DefaultCorsProcessor首先运行
boolean superResult = super.processRequest(config, request, response);
if (!superResult) return false;
ServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
// 如果包含请求私有网络访问的CORS标头,则允许访问
if (serverRequest.getHeaders().containsKey(ACCESS_CONTROL_REQUEST_PRIVATE_NETWORK)) {
response.addHeader(ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK, Boolean.toString(true));
}
return true;
}
}
你可以自定义CorsConfiguration
类以避免硬编码布尔值true
。
然后,在WebSecurityConfig
中使用CustomCorsProcessor
类作为CorsProcessor
。
请注意,在这个私有网络更改之前,CorsConfigurationSource
本身是一个@Bean
,但现在CorsFilter
是@Bean
。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 默认情况下使用名为corsFilter的Bean
.cors()
.and()
// 根据你的应用程序需求添加其他配置
return http.build();
}
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedOrigin("http://domain1.com");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public CorsFilter corsFilter() {
CorsConfigurationSource corsConfigurationSource = corsConfigurationSource();
CorsFilter corsFilter = new CorsFilter(corsConfigurationSource);
// 注册我们的自定义CorsProcessor,包含私有网络允许的标头
corsFilter.setCorsProcessor(new CustomCorsProcessor());
return corsFilter;
}
}
这样可以让Chrome连接到私有网络的Web服务。
这部分部分基于我从以下链接中找到的信息:
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
https://www.baeldung.com/spring-cors
英文:
This is not quite an answer to why your code does not work, but I have just created a Spring way to achieve this, so it may assist you. I am using Spring Boot 2.7 therefore Spring 5.3 is included.
It uses a custom CorsProcessor
class to add the relevant header to the response.
CustomCorsProcessor.java
:
public class CustomCorsProcessor extends DefaultCorsProcessor implements CorsProcessor {
private static final String ACCESS_CONTROL_REQUEST_PRIVATE_NETWORK = "Access-Control-Request-Private-Network";
private static final String ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK = "Access-Control-Allow-Private-Network";
@Override
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
HttpServletResponse response) throws IOException {
//Allow DefaultCorsProcessor to run first
boolean superResult = super.processRequest(config, request, response);
if (superResult == false) return false;
ServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
//If the CORS header requesting Private Network access is present, respond allowing access
if(serverRequest.getHeaders().containsKey(ACCESS_CONTROL_REQUEST_PRIVATE_NETWORK)) {
response.addHeader(ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK, Boolean.toString(true));
}
return true;
}
}
You might like to customise the CorsConfiguration
class to avoid hardcoding the Boolean true
.
Then the CustomCorsProcessor
class is used in WebSecurityConfig
as a CorsProcessor
.
Note that before this Private Network change, the CorsConfigurationSource
was itself an @Bean
but now the CorsFilter
is the @Bean
.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsFilter
.cors()
.and()
... as needed for your application
return http.build();
}
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedOrigin("http://domain1.com");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public CorsFilter corsFilter() {
CorsConfigurationSource corsConfigurationSource = corsConfigurationSource();
CorsFilter corsFilter = new CorsFilter(corsConfigurationSource);
//Register our custom CorsProcessor that includes the Private Network allowed header
corsFilter.setCorsProcessor(new CustomCorsProcessor());
return corsFilter;
}
}
This then allowed Chrome to connect to the Private Network web service.
This is partly based on what I found from these URLs:
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
https://www.baeldung.com/spring-cors
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论