Spring Boot 访问被CORS策略阻止:对预检请求的响应未通过访问控制检查

68bkxrlz  于 2022-11-05  发布在  Spring
关注(0)|答案(9)|浏览(321)

我正在尝试为我的web应用创建一个用户管理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.

角形顶盖配置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 休息用户.服务.ts

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

Spring配置类

@Configuration
@EnableWebMvc
public class SpringConfig implements WebMvcConfigurer {

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

Spring安全配置类

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

}

用户剩余控制器类

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

网络消息

更新日期:2019年6月20日

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);
    });

  }

ctrmrzij

ctrmrzij1#

您可能需要在Sping 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

aiazj4mn

aiazj4mn2#

如果您使用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();
}
ugmeyewa

ugmeyewa3#

由于起始端口4200不同于8080,所以在angular发送create(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");
    }
}

然而,更好的方法是编写一个过滤器(拦截器),它向每个响应添加必要的头部。

e0uiprwp

e0uiprwp4#

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');
qxsslcnc

qxsslcnc5#

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

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

txu3uszq6#

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

xfyts7mz

xfyts7mz7#

如果您在前端使用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/在代码中访问后端
dfty9e19

dfty9e198#

我已经设法在我的php文件中的风箱修复:

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

}

再也没有抱怨了!

wqnecbli

wqnecbli9#

通过互联网尝试了几乎所有的方法,但都不起作用。最后得到了解决方案。如果注入CORS bean,添加@Order(Ordered.HIGHEST_PRECEDENCE)以确保它被注入到Spring config中,并且不被任何其他bean注入阻止。

相关问题