Spring Boot Sping Boot -“Access-Control-Allow-Origin”标头包含多个值,但只能包含一个值

pnwntuvh  于 2023-01-17  发布在  Spring
关注(0)|答案(2)|浏览(299)

我读了StackOverflow上关于这个主题的所有帖子,但没有找到答案,因为它们都是关于不同的场景比我的。
我的spring Boot API使用Spring Security并通过Angular客户端访问。
Angular客户端可以查询各种端点,我的API使用CorsConfigurationsetAllowedOrigins方法将“Access-Control-Allow-Origin“添加为“http://localhost:4200”。
但是,其中一个端点调用另一个API。该API也将其自己的“Access-Control-Allow-Origin“设置为“"。
如果我的客户端查询此终结点,则会出现以下错误:
“**CORS政策:“Access-Control-Allow-Origin”标头包含多个值“http://localhost:4200,
”,但只允许一个值。**”
因此,第二个API添加了带有 * 的头,然后我的API也添加了“http://localhost:4200”,最后在Access-Control-Allow-Origin头中得到了两个条目,如“http://localhost:4200,*"。
我想解决这个问题,但我不知道如何解决。
我的API安全配置正在添加如下CorsConfiguration:

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(...);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                cors()
                .and()
                .csrf().disable()
                .and()
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {

        final CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("*"));

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }
}

我所有的控制器都标注了:

@CrossOrigin(origins = "http://localhost:4200")

上面,我调用setAllowedOrigins(Arrays.asList("http://localhost:4200"))来设置API中的“Access-Control-Allow-Origin”头。
我的API中的所有端点都按预期工作,只有一个端点调用了另一个API。该API还将“Access-Control-Allow-Origin”设置为“”,然后返回到我的API中,导致双精度值:“访问控制允许来源”中的“http://localhost:4200”和“”。
这是我的控制器和服务失败了。如前所述,所有其他的(不调用另一个API)都工作正常。
下面是我的控制器,它调用我下面提供的服务。服务调用成功并返回响应。但是,一旦这个响应发送到客户端,我得到上面的错误。

@RestController
@RequestMapping("/wagen")
@CrossOrigin(origins = "http://localhost:4200")
public class WagenController {

    public WagenController(WagenService service) {
          wagenService = service;
    }

    @PostMapping
    public ResponseEntity<WagenResponse> getWagen(@RequestBody WagenRequest wagenRequest, @RequestHeader HttpHeaders httpHeaders, HttpServletResponse response) {
        ResponseEntity<WagenResponse> wagenResponse = wagenService.getWagen(wagenRequest, httpHeaders);
        return wagenResponse;
    }
}

下面是我的服务。它使用restTemplate调用其他API。所有这些工作正常:

@Override
public ResponseEntity<WagenResponse> getWagen(WagenRequest wagenRequest, HttpHeaders httpHeaders) {
    List<String> authHeader = httpHeaders.get("authorization");
    HttpHeaders headers = new HttpHeaders();
    // add BasicAuth for the other API before calling it in 
    //  below restTemplate call
    headers.add("Authorization", authHeader.get(0)); 

    HttpEntity<WagenRequest> request = new HttpEntity<WagenRequest>(wagenRequest, headers);
    ResponseEntity<WagenResponse> wagenResponse = restTemplate.postForEntity(uri, request, WagenResponse.class);
    return wagenResponse;
}

我如何解决这个问题,使我没有第二个条目在'访问控制-允许-起源'?或一些其他方法?
我没有办法更改其他API发送给我的内容。
下面是开发工具中网络标签的屏幕截图和控制台中显示的错误(这在PostMan中运行良好)。有趣的是,Firefox开发工具显示:

wdebmtf2

wdebmtf21#

问题在于如何调用作为额外CORS标头源的其他API。
在端点中,调用getWagen并检索ResponseEntity作为响应:

@PostMapping
public ResponseEntity<WagenResponse> getWagen(@RequestBody WagenRequest wagenRequest, @RequestHeader HttpHeaders httpHeaders, HttpServletResponse response) {
  ResponseEntity<WagenResponse> wagenResponse = wagenService.getWagen(wagenRequest, httpHeaders);
  return wagenResponse;
}

问题在于如何处理来自Wagen API的响应。
ResponseEntity是来自另一个API的“全部”响应--包括标头。如果在return语句上放置一个断点,您将能够浏览wagenResponse对象,并看到标头包括由另一个API返回的"*" CORS标头。
通过按原样返回ResponseEntity,您将同时返回这些API标头。然后,您应用中的装饰器和注解将在Wagen API返回的标头 * 之上 * 添加CORS标头...这就是问题所在。
getWagen方法返回ResponseEntity<WagenResponse>时,需要挑选出实际需要的位--正文、状态、任何非CORS头--然后生成一个 newResponseEntity返回给调用者。

ccgok5k5

ccgok5k52#

我是Java Sping Boot 的新手,但我是这样处理CORS的:在main()下:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                .allowedOrigins("http://localhost:4200");
        }
    };
}

希望能帮到你!

相关问题