CORS Spring Boot 2.1.2 不发送访问控制标头

Posted

技术标签:

【中文标题】CORS Spring Boot 2.1.2 不发送访问控制标头【英文标题】:CORS SpringBoot 2.1.2 Not Sending access control headers 【发布时间】:2021-12-18 21:49:42 【问题描述】:

感谢您提供的任何帮助。

这看起来很简单,我以前做过,但是...到目前为止,我无法在我的请求响应中获取 CORS 访问控制标头。

我想使用全局配置选项,因为它允许使用方对其端点进行有限控制。 我尝试使用@CrossOrigin 注释进行调试,它似乎也没有返回标头。

我有两个控制器(还有更多,但它们不是我现在需要处理的)

    具有 2 个 GET 端点的状态控制器 /健康 /健康检查 带有 1 个 POST 端点的上传控制器 /上传

我已经阅读了解决问题和正确实施 cors 的各种方法(我们没有使用 spring security)。除非跨源,否则代码可以正常编译和执行。具体来说,我们使用 swagger 来注释我们的代码,当我尝试使用 swagger 测试端点时,它会失败并出现一般的 CORS 错误。

使用 Postman 的 OPTIONS 请求返回:

Allow: POST, OPTIONS

但没有访问控制标头

所以进入代码:

CorsConfig.java

@Configuration
@EnableWebMvc
@PropertySource ("classpath:cors.properties")
@EnableConfigurationProperties (CorsProperties.class)
public class CorsConfig implements WebMvcConfigurer 

    private final CorsProperties corsProperties;

    public CorsConfig(CorsProperties corsProperties) 
        this.corsProperties = corsProperties;
    

    @Override
    public void addCorsMappings(CorsRegistry registry) 

        for (CorsModel model : corsProperties.getModels()) 
            for (String mapping : model.getEndpoints()) 
                registry.addMapping(mapping)
                        .allowedMethods(removeInputQuotes(model.getAllowedMethods()))
                        .allowedHeaders(removeInputQuotes(model.getAllowedHeaders()))
                        .allowedOrigins(removeInputQuotes(model.getAllowedOrigins()))
                        .allowCredentials(false)
// this is a test, adding exposedHeaders did not seem to do anything
                        .exposedHeaders("Access-Control-Allow-Origin")
                        .maxAge(32600);
            
        
    

    private String[] removeInputQuotes(List<String> input) 
        for (int i = 0; i < input.size(); i++) 
            input.set(i, input.get(i).replace("\"", "").replace("'", ""));
        
        return input.toArray(new String[0]);
    

在调试上述内容时,一切似乎都被正确注入,例如所有变量都已设置。

CorsProperties.java

@ConfigurationProperties (prefix = "cors", ignoreUnknownFields = false)
public class CorsProperties 
    public List<CorsModel> models;

    public List<CorsModel> getModels() 
        return models;
    

    public void setModels(List<CorsModel> models) 
        this.models = models;
    

CorsModel.java

public class CorsModel 
    private List<String> endpoints;
    private List<String> allowedOrigins;
    private List<String> allowedHeaders;
    private List<String> allowedMethods;

    public List<String> getEndpoints() 
        return endpoints;
    

    public void setEndpoints(List<String> endpoint) 
        this.endpoints = endpoint;
    

    public List<String> getAllowedOrigins() 
        return allowedOrigins;
    

    public void setAllowedOrigins(List<String> allowedOrigins) 
        this.allowedOrigins = allowedOrigins;
    

    public List<String> getAllowedHeaders() 
        return allowedHeaders;
    

    public void setAllowedHeaders(List<String> allowedHeaders) 
        this.allowedHeaders = allowedHeaders;
    

    public List<String> getAllowedMethods() 
        return allowedMethods;
    

    public void setAllowedMethods(List<String> allowedMethods) 
        this.allowedMethods = allowedMethods;
    

cors.properties

cors.models[0].allowed-headers=*
cors.models[0].allowed-methods=GET,POST,OPTIONS,HEAD
cors.models[0].allowed-origins=*
cors.models[0].endpoints[0]=/health
cors.models[0].endpoints[1]=/healthcheck
cors.models[0].endpoints[2]=/swagger**
cors.models[0].endpoints[3]=/upload

文件控制器.java

@RestController
public class FileController 
    @RequestMapping (path = "/upload", method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<?> upload(@RequestPart ("files") 
    List<MultipartFile> trackFiles) 
    // code to execute, this is an example, I cannot show the internals of this method
    return new ResponseEntity<>(HttpStatus.OK);
    

StatusController.java

@RestController
public class StatusController 
   @GetMapping (value = "/health", produces=MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<HealthCheckResponse> health() 
        RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
        return new ResponseEntity<>(rb.getUptime(), HttpStatus.OK);
    

如果您已经走到了这一步,谢谢! 好吧,那部分我好像没看懂……

我想卷曲端点并在响应中查看访问控制标头

curl -I http://localhost:8080/health
curl -I http://localhost:8080/upload
etc...

卷曲响应:

HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 04 Nov 2021 16:40:48 GMT

据我所知,这是不正确的......它应该看起来像:

HTTP/1.1 200
Date: Thu, 04 Nov 2021 16:55:38 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
access-control-allow-origin: *
access-control-allow-methods: *

我错过了什么?除了给玛丽打个招呼和注射弹簧安全剂,希望这会奏效。

【问题讨论】:

你在用springsecurity吗? 【参考方案1】:

在这方面花了很多时间之后,我曾希望承认...我找到了一个解决方案,将 Cors 过滤合并到拦截器和过滤器中。

将此添加到配置 bean 将设置 cors,而无需在任何地方注入 MVC。

@Bean
    @Order(1)
    public CorsFilter corsFilter() 
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        for (CorsModel model : corsProperties.getModels()) 
            for (String mapping : model.getEndpoints()) 
                final CorsConfiguration configuration = new CorsConfiguration();
                configuration.setAllowedOrigins(removeInputQuotes(model.getAllowedOrigins()));
                configuration.setAllowedMethods(removeInputQuotes(model.getAllowedMethods()));
                configuration.setAllowedHeaders(removeInputQuotes(model.getAllowedHeaders()));
                configuration.setAllowCredentials(true);
                configuration.setMaxAge(32600L);
                configuration.setExposedHeaders(Collections.singletonList("Authorization"));
                source.registerCorsConfiguration(mapping, configuration);
            
        
        return new CorsFilter(source);
    

我的主要 CorsConfig.java 类现在看起来像:

@Configuration
@PropertySource ("classpath:cors.properties")
@EnableConfigurationProperties (CorsProperties.class)
public class CorsConfig 

    private final CorsProperties corsProperties;

    public CorsConfig(CorsProperties corsProperties) 
        this.corsProperties = corsProperties;
    

    @Bean
    @Order(1)
    public CorsFilter corsFilter() 
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        for (CorsModel model : corsProperties.getModels()) 
            for (String mapping : model.getEndpoints()) 
                final CorsConfiguration configuration = new CorsConfiguration();
                configuration.setAllowedOrigins(removeInputQuotes(model.getAllowedOrigins()));
                configuration.setAllowedMethods(removeInputQuotes(model.getAllowedMethods()));
                configuration.setAllowedHeaders(removeInputQuotes(model.getAllowedHeaders()));
                configuration.setAllowCredentials(true);
                configuration.setMaxAge(32600L);
                configuration.setExposedHeaders(Collections.singletonList("Authorization"));
                source.registerCorsConfiguration(mapping, configuration);
            
        
        return new CorsFilter(source);
    

    private List<String> removeInputQuotes(List<String> input) 
        for (int i = 0; i < input.size(); i++) 
            input.set(i, input.get(i).replace("\"", "").replace("'", ""));
        
        return input;
    

【讨论】:

以上是关于CORS Spring Boot 2.1.2 不发送访问控制标头的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 和 CORS

Spring Boot 和 CORS

Spring Boot 和 CORS

Spring Boot 和 CORS

Spring Boot 和 CORS

Spring Boot CORS支持