【问题标题】:Access blocked by CORS policy: Response to preflight request doesn't pass access control check访问被 CORS 策略阻止:对预检请求的响应未通过访问控制检查
【发布时间】:2019-10-22 01:34:33
【问题描述】:

我正在尝试为我的网络应用创建用户管理 API。当我从前端向后端发送 API 调用时,会发生 cors 错误。 cors问题如何解决?我读了很多帖子,但我没有任何进展。

createUser() API 调用后出错

Access to XMLHttpRequest at 'http://localhost:8080/user/create' 
from origin 'http://localhost:4200' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
Redirect is not allowed for a preflight request.

Angular header.config.ts

export const HTTP_OPTIONS = {
  headers: new HttpHeaders({
    'Content-Type':  'application/json',
    'Access-Control-Allow-Credentials' : 'true',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, PUT, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With',
  })
};

Angular rest-user.service.ts

  public createUser() {
    return this.httpClient.post(this.USER_ENDPOINT + 'create', HTTP_OPTIONS);
  }

SpringConfig.class

@Configuration
@EnableWebMvc
public class SpringConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

SpringSecurityConfig.class

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {  
    @Override  
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
        .and().oauth2Client()
        .and().oauth2Login();
    }

}

UserRestController.class

@PostMapping("/user/create")
@ResponseBody
@ResponseStatus(HttpStatus.CREATED)
public void createUser(Principal principal) throws UserAlreadyExistsException {
    userServiceFacadeImpl.createUser(principal.getName());
}

网络消息

更新 20.06.19

  private createUser() {

    const headersObject = new HttpHeaders();

    this.oktaAuth.getAccessToken().then( (value) => {

      headersObject.append('Authorization', 'Bearer ' + value);
      headersObject.append('Content-Type', 'application/json');

      const httpOptions = {
        headers: headersObject
      };

      this.httpClient.post('http://localhost:8080/user/' + 'create', null, httpOptions);
    });

  }

【问题讨论】:

标签: angular spring rest spring-boot http


【解决方案1】:

CORS 标头应从服务器发送。如果你使用 PHP,它会是这样的:

header('Access-Control-Allow-Origin: your-host');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: your-methods like POST,GET');
header('Access-Control-Allow-Headers: content-type or other');
header('Content-Type: application/json');

【讨论】:

    【解决方案2】:

    由于原始端口 4200 与 8080 不同,所以在 Angular 发送创建(PUT)请求之前,它会向服务器发送一个 OPTIONS 请求以检查所有方法和所有访问控制都到位。 服务器必须使用允许的方法和允许的来源列表来响应该 OPTIONS 请求。

    由于你使用的是spring boot,简单的解决方法是添加".allowedOrigins("http://localhost:4200");"

    在你的 spring 配置中,类

    @Configuration
    @EnableWebMvc
    public class SpringConfig implements WebMvcConfigurer {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOrigins("http://localhost:4200");
        }
    }
    

    但是更好的方法是编写一个过滤器(拦截器),它将必要的标头添加到每个响应中。

    【讨论】:

    • 谢谢。我添加了.allowedOrigins("http://localhost:4200"),编写了一个类似link 的过滤器,并从angular 中删除了标题选项。它似乎仍然无法正常工作,我收到以下错误:Access to XMLHttpRequest at 'http://localhost:8080/user/create' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    【解决方案3】:

    您必须在资源的 http 响应中设置 http 标头。所以它需要在服务器端设置,你可以从你的 Angular HTTP-Post 请求中删除“HTTP_OPTIONS”-header。

    【讨论】:

    • 当我从 Angular 中删除选项时,会出现另一个错误:Access to XMLHttpRequest at 'http://localhost:8080/user/create' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 我试图在 spring 中添加一个过滤器,例如link,但它不起作用。
    【解决方案4】:

    您可能需要在 Spring Boot 端配置 CORS。请在您的项目中添加以下类。

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    @EnableWebMvc
    public class WebConfig implements Filter,WebMvcConfigurer {
    
    
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**");
        }
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
          HttpServletResponse response = (HttpServletResponse) res;
          HttpServletRequest request = (HttpServletRequest) req;
          System.out.println("WebConfig; "+request.getRequestURI());
          response.setHeader("Access-Control-Allow-Origin", "*");
          response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
          response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,observe");
          response.setHeader("Access-Control-Max-Age", "3600");
          response.setHeader("Access-Control-Allow-Credentials", "true");
          response.setHeader("Access-Control-Expose-Headers", "Authorization");
          response.addHeader("Access-Control-Expose-Headers", "responseType");
          response.addHeader("Access-Control-Expose-Headers", "observe");
          System.out.println("Request Method: "+request.getMethod());
          if (!(request.getMethod().equalsIgnoreCase("OPTIONS"))) {
              try {
                  chain.doFilter(req, res);
              } catch(Exception e) {
                  e.printStackTrace();
              }
          } else {
              System.out.println("Pre-flight");
              response.setHeader("Access-Control-Allow-Origin", "*");
              response.setHeader("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT");
              response.setHeader("Access-Control-Max-Age", "3600");
              response.setHeader("Access-Control-Allow-Headers", "Access-Control-Expose-Headers"+"Authorization, content-type," +
              "USERID"+"ROLE"+
                      "access-control-request-headers,access-control-request-method,accept,origin,authorization,x-requested-with,responseType,observe");
              response.setStatus(HttpServletResponse.SC_OK);
          }
    
        }
    
    }
    

    更新:

    要将令牌附加到每个请求,您可以创建一个拦截器,如下所示。

    import { Injectable } from '@angular/core';
    import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
    import { Observable } from 'rxjs';
    
    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const token = window.localStorage.getItem('tokenKey'); // you probably want to store it in localStorage or something
    
    
        if (!token) {
          return next.handle(req);
        }
    
        const req1 = req.clone({
          headers: req.headers.set('Authorization', `${token}`),
        });
    
        return next.handle(req1);
      }
    
    }
    

    Example

    【讨论】:

    • 你用上面的 SpringConfig 类替换了吗,请删除 Angular 上的标头配置,然后重试,让我们知道结果
    • 我做了,但我得到了这个错误:Access to XMLHttpRequest at 'http://localhost:8080/user/create' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    • 您好@laprof 确保您已将 Token 添加到 Header。转到网络选项卡并检查标题应该使用您的令牌进行授权
    • 我已经在帖子更新中添加了如上所示的令牌,但它没有出现在标题中。
    • 只是一个小改动。还在 response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,observe") 中添加“Accept”;接受多部分请求。
    【解决方案5】:

    您可以将所需的 CORS 配置创建为 bean。根据下面的代码,这将允许来自任何来源的所有请求。 这有利于发展,但不安全。 Spring Docs

    @Bean
    WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
            }
        }
    }
    

    【讨论】:

      【解决方案6】:

      如果您使用 Spring 作为后端服务器,尤其是使用 Spring Security,那么我通过将 http.cors(); 放入 configure 方法中找到了解决方案。方法如下:

      protected void configure(HttpSecurity http) throws Exception {
              http
                      .csrf().disable()
                      .authorizeRequests() // authorize
                      .anyRequest().authenticated() // all requests are authenticated
                      .and()
                      .httpBasic();
      
              http.cors();
      }
      

      【讨论】:

      • 添加 http.cors() 对我有用,非常感谢!
      • 那个“.httpBasic();”将我从春季启动时遇到的 403 禁止错误中救了出来。非常感谢:D
      【解决方案7】:

      如果你在前端使用 Angular CLI,那么

      • 在你的根目录下创建proxy.conf.json并添加以下内容
      {
      
         "/api": {
           "target": "your backend url",
           "secure": true,
           "changeOrigin": true,
           "pathRewrite": {
             "^/api": ""
           }
         }
       }
      
      • 使用此命令运行您的开发服务器ng serve --proxy-config proxy.conf.json
      • 您将在代码中使用基本 URL ${your frontend url}/api/ 访问您的后端

      【讨论】:

        【解决方案8】:

        我已经设法修复了我的 php 文件中的波纹管:

        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            // The request is using the POST method
            header("HTTP/1.1 200 OK");
            return;
        
        }
        

        没有更多的抱怨!

        【讨论】:

          猜你喜欢
          • 2020-09-30
          • 2019-04-17
          • 2019-12-14
          • 1970-01-01
          • 2020-01-23
          • 2022-07-01
          • 2019-04-11
          • 1970-01-01
          相关资源
          最近更新 更多