在带有 Angular 的 Spring Boot 中启用了 Cors,但仍然出现 cors 错误

Posted

技术标签:

【中文标题】在带有 Angular 的 Spring Boot 中启用了 Cors,但仍然出现 cors 错误【英文标题】:Cors enabled in Spring Boot with Angular, still cors errors 【发布时间】:2021-03-01 16:37:07 【问题描述】:

我为所有来源和标头启用了 cors,但是当我从我的 angular 应用程序调用 get 方法到 spring boot 时,我仍然收到 cors 错误。

来自控制台的 Cors 错误:

Access to XMLHttpRequest at 'http://localhost:8080/api/users/test@ronny.nl' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我的controller(我叫getbyemail):

@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
@RequestMapping(value = "/api/users", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController 

    private final UserService userService;

    @Autowired
    public UserController(final UserService userService) 
        this.userService = userService;
    

    @GetMapping
    public List<UserDTO> getAllUsers() 
        return userService.findAll();
    

    @GetMapping("/id")
    public UserDTO getUser(@PathVariable final Long id) 
        return userService.get(id);
    

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @GetMapping("/email")
    public UserDTO getUserByMail(@PathVariable String email) 
        return userService.getByEmail(email);
    

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Long createUser(@RequestBody @Valid final UserDTO userDTO) 
        return userService.create(userDTO);
    

    @PutMapping("/id")
    public void updateUser(@PathVariable final Long id, @RequestBody @Valid final UserDTO userDTO) 
        userService.update(id, userDTO);
    

    @DeleteMapping("/id")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteUser(@PathVariable final Long id) 
        userService.delete(id);
    


我从我的 Angular 应用中调用 get 的地方:

onSubmit(): void 
    this.submitted = true;
    this.wrongInput = false;
    this.loginService.getLogin<User>(this.loginForm.value.email).subscribe((response) => 
      this.tempUser = response;
      console.log(this.tempUser);
      if (this.loginForm.value.email === this.tempUser.email && this.loginForm.value.password === this.tempUser.password) 
        this.localStorageService.save(this.tempUser);
        this.router.navigate(['/home']);
        console.log(true);
      
      else 
        this.wrongInput = true;
      
    );
  

我也尝试添加DevCorsConfiguration

package com.team13.triviaquiz.triviaquizserver.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@Profile("development")
public class DevCorsConfiguration implements WebMvcConfigurer 

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        registry.addMapping("/api/**").allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS");
    

并在我的application.properties 中添加了个人资料:

application.properties
spring.profiles.active=development
#enabling h2 console
spring.h2.console.enabled=true
#fixed URL for H2 (necessary from Spring 2.3.0)
spring.datasource.url=jdbc:h2:mem:triviaquizserver
#turn statistics on
spring.jpa.properties.hibernate.generate_statistics = true
logging.level.org.hibernate.stat=debug
#show all queries
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type=trace

但还是没有运气......

【问题讨论】:

【参考方案1】:

在您的控制器上尝试以下操作

@CrossOrigin(origins = "*", allowCredentials = "true", allowedHeaders = "*", exposedHeaders = "If-Match")

【讨论】:

然后我得到另一个错误:当 allowCredentials 为真时,allowedOrigins 不能包含特殊值“*”,因为它不能在“Access-Control-Allow-Origin”响应标头上设置。要允许一组来源的凭据,请明确列出它们或考虑改用“allowedOriginPatterns”。 我能够通过在 WebSecurityConfig 上使用 addAllowedOriginPattern(*) 来解决此问题。【参考方案2】:

cors 错误来自为我的两个 get 方法处理不明确的处理程序错误。 我的controller 中有两个get 方法,一个是integer,另一个是String。所以它无法真正弄清楚解析字符串或 int(我认为)我已将 get 方法的 bot 路径更改为:

 @GetMapping("/id/id")
    public UserDTO getUser(@PathVariable final Long id) 
        return userService.get(id);
    

    @GetMapping("/email/email")
    public UserDTO getUserByMail(@PathVariable String email) 
        return userService.getByEmail(email);
    

这也修复了 @CrossOrigin(origins = "*", allowedHeaders = "*") 的 cors 错误 在controller

【讨论】:

【参考方案3】:

这可能是由于 Spring 库的更改,从而影响了 Spring Boot 2.4.0。 看这里https://github.com/spring-projects/spring-framework/issues/26111 及其相关票证https://github.com/spring-projects/spring-framework/pull/26108

编辑 这是来自第一个链接的原始消息:

#25016 引入了除了 allowedOrigins 之外还可以配置 allowedOriginPatterns 的功能。它让您定义更灵活 模式,而后者实际上是返回的值 Access-Control-Allow-Origin 标头,并且不允许使用“*” 与 allowCredentials=true 组合。引入的变化 WebMvc 和 WebFlux 中的等效 allowedOriginPatterns 方法 config,但不在 SockJS 配置和 AbstractSocketJsService 中。

我将为 5.3.2 添加这些内容。然后你需要切换到 allowedOriginPatterns 而不是 allowedOrigins 但这会给你一个 更精确地定义允许的域模式的选项。在里面 同时,您可以通过列出特定的 域,如果可行的话。

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review 有道理,编辑了答案。谢谢提示【参考方案4】:

这个问题背后的原因在answer中已经明确提到了,简单地说CorsRegistry#allowCredentials(true)不能与默认值CorsRegistry#allowedOrigins()一起使用(默认情况下,如果您没有设置此属性,则允许所有来源,除非任何CorsRegistry#allowedOriginPatterns() 已设置)

用最典型的 Spring boot corsMappings 阐明问题:
    @Bean
    public WebMvcConfigurer corsConfigurer() 
        return new WebMvcConfigurer() 
            @Override
            public void addCorsMappings(CorsRegistry registry) 
                registry.addMapping("/**").allowedMethods("*").allowCredentials(true);
            
        ;
    

在上面的例子中allowCredentials被设置为true,同时allowedOrigins没有被配置,这意味着默认情况下所有的来源都是允许的(allowedOrigins的值将是*)。

要解决此问题,您必须明确设置allowedOriginsallowedOriginPatterns。 在下面的代码 sn-p 中,使用了 allowedOriginPatterns,并将值设置为 -> "https://*.domain.com"。此通配符模式匹配来自 domain.com 的任何主机和诸如 https:microservice.division.domain.com 之类的 url 模式
    @Bean
    public WebMvcConfigurer corsConfigurer() 
        return new WebMvcConfigurer() 
            @Override
            public void addCorsMappings(CorsRegistry registry) 
                registry.addMapping("/**").allowedMethods("*").allowedOriginPatterns("https://*.domain.com");
            
        ;
    

完整代码sn -p link

【讨论】:

【参考方案5】:

我收到错误时的情景是:

我已经在我的 Spring Boot 服务器应用程序中添加了 Spring Boot 安全依赖项。

与您的跟踪类似,我添加了 CrossOrigin() 注释来解决问题。但问题并没有得到解决。

我通过在请求的标头选项中添加基本身份验证解决了这个问题。

在header中添加基本认证请参考帖子:

Angular 6 HTTP Get request with HTTP-Basic authentication

import  HttpHeaders  from '@angular/common/http';

const httpOptions = 
headers: new HttpHeaders(
'Content-Type':  'application/json',
'Authorization': 'Basic ' + btoa('username:password')
)
;

用您的用户名和密码替换用户名和密码。 默认情况下,Spring boot 中的用户名是“user”,密码将在启动 Spring Boot 应用程序的控制台上生成。

注意:您还必须将 CrossOrigin Annotation 添加到您的 RequestMapping 中。

由于您使用的是基本身份验证,您应该添加 WebSecurityConfiguration 以允许安全配置如下:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 
    
    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
        http.cors();
    

参考资料:

https://www.baeldung.com/spring-security-cors-preflight https://www.baeldung.com/spring-security-basic-authentication

希望解决方案对您有所帮助。

谢谢 昌都

【讨论】:

【参考方案6】:

更改corsConfiguration.setAllowedOrigins("*") corsConfiguration.setAllowedOriginPatterns("*") 为我成功了!

所以基本上是setAllowedOriginssetAllowedOriginPatterns

【讨论】:

【参考方案7】:

你应该创建一个名为“”的类,代码如下

package com.api.juego.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer 

    private final long MAX_AGE_SECS = 3600;

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        registry.addMapping("/**")
        .allowedOrigins("*")
        .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
        .allowedHeaders("*")
        .allowCredentials(false)
        .maxAge(MAX_AGE_SECS);
    

出于安全原因,允许的方法是 GET、POST、PUT、PATCH、DELETE 和 OPTIONS。

【讨论】:

以上是关于在带有 Angular 的 Spring Boot 中启用了 Cors,但仍然出现 cors 错误的主要内容,如果未能解决你的问题,请参考以下文章

带有spring boot LDAP身份验证的Angular2

带有 Spring Boot 和 Spring Security 的 Angular2

带有 Keycloak 的 Angular/Spring Boot 抛出 403

在 Angular5 和 Spring Boot 中上传带有 JSON 数据的文件

获取 JWT 后,带有 Spring Boot 后端的 Angular 在现有路由上返回 404

在带有 Angular 的 Spring Boot 中启用了 Cors,但仍然出现 cors 错误