programing

CORS 정책에 의해 액세스가 차단되었습니다.비행 전 요청에 대한 응답이 액세스 제어 검사를 통과하지 못했습니다.

golfzon 2023. 4. 4. 22:38
반응형

CORS 정책에 의해 액세스가 차단되었습니다.비행 전 요청에 대한 응답이 액세스 제어 검사를 통과하지 못했습니다.

웹 앱용 사용자 관리 API를 만들려고 합니다.프런트엔드에서 백엔드로 API 콜을 전송하면 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',
  })
};

각도 rest-user.service.ts

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

Spring Config.class

@Configuration
@EnableWebMvc
public class SpringConfig implements WebMvcConfigurer {

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

Spring Security Config.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);
    });

  }

여기에 이미지 설명 입력

스프링 부트측에서 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);
  }

}

백엔드 서버로 스프링을 사용하고 특히 스프링 보안을 사용하는 경우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();
}

발신기지 포트 4200은 8080과는 다르기 때문에 angular는 작성(PUT) 요구를 송신하기 전에 OPTIONS 요구를 서버에 송신하여 모든 메서드와 모든 접근컨트롤이 설정되어 있는지 확인합니다.서버는 OPTIONS 요청에 허용된 메서드와 허용된 원본 목록을 사용하여 응답해야 합니다.

스프링 부트를 사용하고 있기 때문에, 간단한 해결책은,".allowedOrigins("http://localhost:4200");"

스프링 구성, 클래스

@Configuration
@EnableWebMvc
public class SpringConfig implements WebMvcConfigurer {

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

그러나 더 나은 방법은 각 응답에 필요한 헤더를 추가하는 필터(인터셉터)를 쓰는 것입니다.

서버로부터 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');

필요한 CORS 설정을 빈으로 작성할 수 있습니다.아래 코드와 같이 모든 발신기지로부터의 요청이 허용됩니다.이것은 개발에는 좋지만 불안정하다.스프링 문서

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

http 헤더는 리소스의 http 응답으로 설정해야 합니다.따라서 서버 측으로 설정해야 하며 각 HTTP-Post 요청에서 "HTTP_OPTIONS" 헤더를 제거할 수 있습니다.

프런트 엔드에서 Angular CLI를 사용하는 경우

  • 작성하다proxy.conf.jsonroot 디렉토리에서 다음을 수행합니다.
{

   "/api": {
     "target": "your backend url",
     "secure": true,
     "changeOrigin": true,
     "pathRewrite": {
       "^/api": ""
     }
   }
 }
  • 이 명령으로 개발 서버 실행ng serve --proxy-config proxy.conf.json
  • 기본 URL을 사용하여 코드의 백엔드에 액세스합니다.${your frontend url}/api/

나는 내 php 파일의 bellow로 간신히 수정했다:

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

}

더 이상 불평은 없어!

인터넷을 통해 거의 모든 방법을 시도했지만 효과가 없었습니다.드디어 해결책을 찾았다.CORS bean을 주입할 경우 @Order(주문)를 추가합니다.HIGHT_PRECEDION)을 사용하여 스프링 구성으로 주입되며 다른 빈 주입에 의해 차단되지 않음을 확인합니다.

언급URL : https://stackoverflow.com/questions/56479150/access-blocked-by-cors-policy-response-to-preflight-request-doesnt-pass-access

반응형