programing

스프링 부트 CORS 필터 - CORS 프리플라이트 채널에 성공하지 못함

closeapi 2023. 3. 17. 21:30
반응형

스프링 부트 CORS 필터 - CORS 프리플라이트 채널에 성공하지 못함

스프링 부트 웹 응용 프로그램에 CORS 필터를 추가해야 합니다.

다음 매뉴얼에 기재되어 있는 바와 같이 CORS 매핑을 추가했습니다.http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html

설정은 다음과 같습니다.

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // @formatter:off   
        registry
            .addMapping("/**")
            .allowedOrigins(CrossOrigin.DEFAULT_ORIGINS)
            .allowedHeaders(CrossOrigin.DEFAULT_ALLOWED_HEADERS)
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
            .maxAge(3600L);
        // @formatter:on
    }

...

}

지금 API에 접속하려고 하면 다음 오류가 나타납니다.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com/api/v1.0/user. (Reason: CORS preflight channel did not succeed).

다음은 FF 콘솔의 스크린샷입니다.

여기에 이미지 설명 입력

이 문제를 피하기 위해 CORS 헤더를 올바르게 설정하는 방법은 무엇입니까?

새로운 CORS 필터를 생성하여 이 문제를 해결했습니다.

@Component
public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, xsrf-token");
        response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else { 
            filterChain.doFilter(request, response);
        }
    }
}

보안 설정에 추가했습니다.

.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class)

최신 정보 - 최근 더 현대적인 방식으로 변경:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .cors()
        .and()

        ...
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
        configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}

스프링 데이터 레스트에 CORS를 사용하는 것과 같은 문제가 있었습니다만, 이것이 제가 사용한 필터 코드입니다.

    /**
 * Until url{https://jira.spring.io/browse/DATAREST-573} is fixed
 * 
 * @return
 */
@Bean
public CorsFilter corsFilter() {

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    //config.setAllowCredentials(true); // you USUALLY want this
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("HEAD");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

이것은 매우 간단하고 잘 작동합니다.[ Configurations 에에 [Web Security Configurations]라고 합니다.httpSecury.cors();


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

         httpSecurity.cors();     //  This enables cors

        // Your codes

    }

}


두 가지 튜토리얼을 따라도 여전히 CORS 오류가 발생하였습니다.

먼저 웹 보안 가이드 https://spring.io/guides/gs/securing-web/ #http://filename에 따라 실행했습니다.

두 번째로는 CORS 가이드 https://spring.io/guides/gs/rest-service-cors/ #global-global-configuration에 따릅니다.

한 후 저는 '아예'를 추가해야 .http.cors()http http http 。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.cors()
  .and()
    ...
} 

의 추가.cors()에서는 을 할 수 있습니다.@BeanCORS를 사용하다

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

다음과 같은 조합 솔루션이 효과가 있었습니다.

1.

@Configuration
public class CorsConfiguration {

//This can be used in combination with @CrossOrigin on the controller & method.

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("HEAD","OPTIONS")
                        .allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept");
            }
        };
    }
}

2. @CrossOriginRest Controller rest rest rest rest 。 있다@CrossOrigin@RequestMapping「HTTP」입니다.CORS를 사용하다

그러나 프로젝트에 스프링 보안을 사용하려는 경우 위의 솔루션을 사용할 수 없게 됩니다.

스프링 부트 버전 1.5.4를 사용하고 있습니다.풀어주다.

나에겐 일인데

@Configuration
public class CorsConfig implements WebMvcConfigurer {

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

스프링 시큐러티와 함께 CORS를 사용하고 있는 경우는, 다음의 최신 메뉴얼을 참조해 주세요.https://docs.spring.io/spring-security/site/docs/current/reference/html5/ # http://https://docs.spring.io/spring-security/site/docs/current/reference/html5/

이 페이지의 다른 부분에 인용된 코드와 유사합니다.

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // by default uses a Bean by the name of corsConfigurationSource
            .cors(withDefaults())
            ...
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

CORS를 설정할 수 있는 장소는 그 밖에도 있습니다만, 보안 설정의 일부로서 설정하는 것이 좋습니다.이는 보안 처리 전에 CORS 처리가 실행되어야 한다는 점에서 매우 밀접하게 관련되어 있기 때문입니다.이것은 이전 투고에서 설명한 것입니다.위의 인용 문서에 기재되어 있는 이유는 다음과 같습니다.

"사전 요청에는 쿠키(JSESSIONID)가 포함되지 않기 때문에 스프링 보안 전에 CORS를 처리해야 합니다.요청에 쿠키가 포함되어 있지 않고 Spring Security가 처음인 경우 요청에 의해 사용자가 인증되지 않았음이 판단되어 거부됩니다.(요구에 쿠키가 없기 때문에).

위와 같이 http 설정의 선두에 .cors() 행을 추가하면 그렇게 됩니다.그렇지 않으면 비행 전 OPTIONS 요청이 응답하지 않습니다.

코드 아래의 스프링 부트 2를 사용하여 코르스 문제 및 비행 전 문제를 해결할 수 있는지 여부

@Override
    public void configure(WebSecurity web) throws Exception {
//      web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
        web.ignoring().antMatchers("/resources/**", "/index.html", "/login.html", "/partials/**", "/template/**", "/",
                "/error/**", "/h2-console", "*/h2-console/*");
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.applyPermitDefaultValues();
        config.setAllowCredentials(true);// this line is important it sends only specified domain instead of *
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }

이것은 스프링 부츠와 함께 동작하기 위해 Cors Configurations에서 사용한 코드입니다.메인 애플리케이션 클래스의 corsFilter 구성입니다.

응용 프로그램이 'http://localhost: 4200'에서 실행되고 있습니다.

import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;


    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        corsConfiguration.setAllowedHeaders(Arrays.asList("Origin", "Access-Control-Allow-Origin", "Content-Type",
                "Accept", "Authorization", "Origin, Accept", "X-Requested-With",
                "Access-Control-Request-Method", "Access-Control-Request-Headers"));
        corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization",
                "Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
        corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }


사전 실행 OPTIONS 요청을 적절하게 처리해야 하지만 교차 사이트 리소스 요청이 작동하기에 충분하지 않습니다.

OPTIONS 요청이 만족스러운 헤더로 돌아온 후 동일한 URL에 대한 후속 요청에 대한 모든 응답에는 필요한 "Access-Control-Allow-Origin" 헤더가 있어야 합니다. 그렇지 않으면 브라우저가 해당 헤더를 삼켜 디버거 창에 표시되지 않습니다.https://stackoverflow.com/a/11951532/5649869

현재 권장되는 CORS 방법은

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(true).maxAge(3600);

        // Add more mappings...
    }
}

이것은, https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors 를 베이스로 하고 있습니다.

단, Web Security Config 파일에서 CORS가 네이블이고 CSRF가 디세이블인지도 확인해야 합니다.

이전에 GET 메서드는 정상적으로 동작하지만 POST 메서드는 모두 동작하지 않는 문제(반환 금지 403)가 있었습니다만, CSRF를 무효로 하면 해결됩니다.

순서 1: 컨트롤러에 이 주석을 추가합니다.

@CrossOrigin
public class JobController {}

순서 2: 임의의 설정에 추가

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

이것은 컨트롤러에 @CrossOrigin 주석이 있는 경우에만 작동합니다.

AFAIK는 모든 http 요구에 대해 해당 특정 API 요청의 액세스를 확인하기 위해 프리플라이트 요구가 서버로 전송됩니다.프리플라이트 요구는 통상, 다음의 요구에 필요한 메타데이터를 송신하는 「OPTION」http 요구입니다.

따라서 "preflight channel successed" 오류는 서버에 전송된 preflight 요구가 차단 또는 거부되었음을 의미합니다.대부분의 경우, 이것은

  • "OPTION" 요청이 스프링 보안 구성에 허용된 메서드에 없습니다.
  • 사용자 UI의 원본이 스프링 보안에서 허용되지 않습니다.

Spring security 5.4.5에서는 기본적으로 위의 점에 대해 이것이 근본적인 문제인지 여부를 확인할 수 있습니다.

WebMvcConfigr를 확장하는 클래스를 만들거나 업데이트합니다.

@Override
public void addCorsMappings(CorsRegistry registry) {
    //The pattern, allowedOrigins and allowedMethods should be restricted to the frontend application url,
    //so that CORS attacks won't happen
    registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}

여기서 add Mapping은 "API 엔드포인트"의 파라미터를 사용합니다.서버에서 지원되는 모든 엔드포인트를 구성하기 위해 "*"를 제공합니다.

allowedOrigins는 앞에서 설명한 매핑에 대해 지원되는 UI 애플리케이션 경로에 해당합니다(*).

allowed Methods는 서버에 허용된 모든 http 메서드의 배열을 사용합니다.

실제 가동 환경에서는 이 구성을 적절한 값으로 제한해야 합니다.

또한 Web Security Configurer Adapter를 확장하는 설정 클래스에서도

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors()
            .and()
            .......
            .authenticated();
}

여기서 설명한 'http.cors()' 메서드에 주의해 주십시오.

언급URL : https://stackoverflow.com/questions/36809528/spring-boot-cors-filter-cors-preflight-channel-did-not-succeed

반응형