복붙노트

[SPRING] Spring Boot + Spring Security 애플리케이션에서 CORS를 구성하는 방법은 무엇입니까?

SPRING

Spring Boot + Spring Security 애플리케이션에서 CORS를 구성하는 방법은 무엇입니까?

나는 Spring Security와 Cors Support로 Spring Boot를 사용한다.

다음 코드를 실행하면

url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
    if xmlhttp.readyState is 4
        console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send

나는 결과로 얻는다.

200

내가 잘못된 자격 증명으로 테스트하면

url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
    if xmlhttp.readyState is 4
        console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:aa'
do xmlhttp.send

401 (스프링 보안에서 잘못된 인증을위한 표준 코드)을 얻지 않고

0

다음 브라우저 알림과 함께 :

GET http : // localhost : 5000 / api / token

XMLHttpRequest는 http : // localhost : 5000을로드 할 수 없습니다. 'Access-Control-Allow-Origin'헤더가 요청 된 리소스에 없습니다. 따라서 'http : // localhost : 3000'은 액세스가 허용되지 않습니다. 응답에는 HTTP 상태 코드 401이 있습니다.

상황을 처리하기 위해 서버 응답에서 유용한 http 상태 코드가 필요한 프론트 엔드 코드를 개발 중입니다. 0보다 유용한 뭔가가 필요합니다. 응답 본문도 비어 있습니다. 내 구성이 잘못되었거나 소프트웨어 버그인지 잘 모르겠다. 크롬 (아치 리눅스 사용)이나 스프링 보안이 어디에 있는지도 모른다.

My Spring Config는 다음과 같습니다.

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@RestController
@RequestMapping("api")
public class Controller {
    @RequestMapping("token")
    @CrossOrigin
    Map<String, String> token(HttpSession session) {
        return Collections.singletonMap("token", session.getId());
    }
}

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .anyRequest().authenticated()
                .and().httpBasic();
    }
}

모든 것을 꼬아 서 테스트하면 CORS 지원이 필요 없기 때문에 생각 하겠지만 CORS를 OPTION 요청으로 시뮬레이트하려고 했으므로 결과도 괜찮습니다.

$ curl -v localhost:5000/api/token -H "Authorization: Basic YTpha"
*   Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTpha
> 
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Access-Control-Allow-Origin: http://localhost:3000
< Access-Control-Allow-Methods: POST,GET,OPTIONS,DELETE
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin,Accept,X-Requested-    With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
< x-auth-token: 58e4cca9-7719-46c8-9180-2fc16aec8dff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:15:44 GMT
< 
* Connection #0 to host localhost left intact
{"token":"58e4cca9-7719-46c8-9180-2fc16aec8dff"}

잘못된 자격 증명으로

$ curl -v localhost:5000/api/token -H "Authorization: Basic YTp"
*   Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTp
> 
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< WWW-Authenticate: Basic realm="Realm"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:16:15 GMT
< 
* Connection #0 to host localhost left intact
{"timestamp":1462119375041,"status":401,"error":"Unauthorized","message":"Failed to decode basic authentication token","path":"/api/token"}

편집하다: 오해를 피하기 위해서. 나는 1.3.3 Spring Boot를 사용한다. 블로그 게시물은 다음과 같이 씁니다 :

전역 코드 지원을 사용하려면 다음 코드를 추가했습니다. 실제로 전에 이것을 시도했지만 그 결과는 같았습니다. 최근에 다시 시도했는데 그 결과는 같습니다.

@Configuration
public class MyConfiguration {

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

문제는 인증 프로세스간에 리디렉션으로 인해 발생한다는 생각은 흥미 롭습니다. 이 충돌을 피하기 위해 리소스로 리디렉션을 어떻게 바꿀 수 있습니까?

편집하다:

나는 해결책에 더 가깝다고 생각한다. 나는 추가하여 문제없이 cors를 지원하는 nodejs 서버를 테스트했다. 액세스 제어 허용 - 원본 : * 모든 요청에.

스테판 이젤 (Stefan Isele)은 이미 봄 보안이 리다이렉트하거나 CORS 헤더를 추가하지 않아서 요청이 깨진 것 같다고 언급했다. 따라서 스프링 보안이 인증을 확인하는 동안 적절한 헤더를 추가해야합니다.

아무도 그렇게하는 방법을 알고 있습니까?

편집하다:

나는 추악한 것 같은 해결 방법을 발견했다. 스프링 쿨러에 대한 github 문제를 해결 방법을 설명합니다 : https://github.com/spring-projects/spring-boot/issues/5834

해결법

  1. ==============================

    1.스프링 시큐리티는 이제 필자가 작성한이 블로그 게시물에서 설명하는 스프링 MVC CORS 지원을 활용할 수 있습니다.

    스프링 시큐리티는 이제 필자가 작성한이 블로그 게시물에서 설명하는 스프링 MVC CORS 지원을 활용할 수 있습니다.

    이 기능을 사용하려면 다음과 같이 스프링 보안 레벨에서 CORS 지원을 명시 적으로 활성화해야합니다. 그렇지 않으면 CORS 사용 가능 요청이 스프링 MVC에 도달하기 전에 스프링 보안에 의해 차단 될 수 있습니다.

    컨트롤러 레벨 @CrossOrigin 주석을 사용하고 있다면 스프링 보안 CORS 지원을 활성화하면 스프링 MVC 설정을 활용할 수 있습니다.

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and()...
        }
    }
    

    CORS 전역 구성을 사용하는 것을 선호하는 경우 다음과 같이 CorsConfigurationSource Bean을 선언 할 수 있습니다.

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and()...
        }
    
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
            return source;
        }
    }
    

    이 방법은 이전에 권장 된 필터 기반 방식보다 우선합니다.

    자세한 내용은 Spring Security 문서의 전용 CORS 섹션을 참조하십시오.

  2. ==============================

    2.스프링 보안을 사용하는 경우 다음을 수행하여 CORS 요청이 먼저 처리되도록 할 수 있습니다.

    스프링 보안을 사용하는 경우 다음을 수행하여 CORS 요청이 먼저 처리되도록 할 수 있습니다.

    @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().and()
                ...
        }
    
        @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;
        }
    }
    

    자세한 정보는 Spring 4.2.x CORS를 참조하십시오.

  3. ==============================

    3.JDK 8 이상을 사용하는 경우, 람다 솔루션은 한 줄로 구성됩니다.

    JDK 8 이상을 사용하는 경우, 람다 솔루션은 한 줄로 구성됩니다.

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
    }
    
  4. ==============================

    4.Cross origin protection은 브라우저의 기능입니다. Curl은 CORS에 관심이 없습니다. 브라우저 요구가 그렇지 않은데 왜 당신의 컬이 성공했는지 설명합니다.

    Cross origin protection은 브라우저의 기능입니다. Curl은 CORS에 관심이 없습니다. 브라우저 요구가 그렇지 않은데 왜 당신의 컬이 성공했는지 설명합니다.

    잘못된 자격 증명으로 브라우저 요청을 보내면 spring은 클라이언트를 로그인 페이지로 전달하려고 시도합니다. 이 응답 (로그인 페이지 제외)에는 'Access-Control-Allow-Origin'헤더가 없으며 사용자가 설명하는대로 브라우저가 반응합니다.

    이 로그인 응답의 헤더를 포함하려면 봄을 사용해야하고 오류 페이지와 같은 다른 응답이 필요할 수 있습니다.

    이것은 다음과 같이 할 수 있습니다 :

        @Configuration
        @EnableWebMvc
        public class WebConfig extends WebMvcConfigurerAdapter {
    
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/api/**")
                        .allowedOrigins("http://domain2.com")
                        .allowedMethods("PUT", "DELETE")
                        .allowedHeaders("header1", "header2", "header3")
                        .exposedHeaders("header1", "header2")
                        .allowCredentials(false).maxAge(3600);
                }
         }
    

    이것은 cors-in-spring-framework에서 복사됩니다.

    모든 리소스에 대해 cors 매핑을 추가하여 시작합니다.

    registry.addMapping("/**")
    

    또한 모든 메소드 헤더를 허용합니다. 일단 작동하면 필요한 최소량으로 다시 줄이기 시작할 수 있습니다.

    릴리스 4.2에서는 CORS 구성이 변경된다는 점에 유의하십시오.

    이렇게해도 문제가 해결되지 않으면 실패한 ajax 요청에서 얻은 응답을 게시하십시오.

  5. ==============================

    5.속성 구성의 경우

    속성 구성의 경우

    # ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
    endpoints.cors.allow-credentials= # Set whether credentials are supported. When not set, credentials are not supported.
    endpoints.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
    endpoints.cors.allowed-methods=GET # Comma-separated list of methods to allow. '*' allows all methods.
    endpoints.cors.allowed-origins= # Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
    endpoints.cors.exposed-headers= # Comma-separated list of headers to include in a response.
    endpoints.cors.max-age=1800 # How long, in seconds, the response from a pre-flight request can be cached by clients.
    
  6. ==============================

    6.나는이 문제를 다음과 같이 해결했다. `

    나는이 문제를 다음과 같이 해결했다. `

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers","Access-Control-Allow-Origin","Access-Control-Request-Method", "Access-Control-Request-Headers","Origin","Cache-Control", "Content-Type", "Authorization"));
        configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    

    `

  7. ==============================

    7.Cors는 엉덩이에 통증이 될 수 있지만,이 간단한 코드로 Cors 만 !!!! 지정된 메소드에

    Cors는 엉덩이에 통증이 될 수 있지만,이 간단한 코드로 Cors 만 !!!! 지정된 메소드에

    @CrossOrigin(origins="*")// in this line add your url and thats is all for spring boot side
        @GetMapping("/some")
        public String index() {
            return "pawned cors!!!!";
        }
    

    봄 부츠 2.0.2의 매력처럼

  8. ==============================

    8.Spring-Boot, Spring-Security 및 Java 기반 구성을위한 쉬운 솔루션을 찾았습니다.

    Spring-Boot, Spring-Security 및 Java 기반 구성을위한 쉬운 솔루션을 찾았습니다.

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.cors().configurationSource(new CorsConfigurationSource() {
                @Override
                public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                    return new CorsConfiguration().applyPermitDefaultValues();
                }
            });
        }
    }
    
  9. ==============================

    9.나는이 문제를 다음과 같이 해결했다.

    나는이 문제를 다음과 같이 해결했다.

    @Configuration
    public class CORSFilter extends CorsFilter {
    
        public CORSFilter(CorsConfigurationSource source) {
            super((CorsConfigurationSource) source);
        }
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
    
            response.addHeader("Access-Control-Allow-Headers",
                    "Access-Control-Allow-Origin, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
            if (response.getHeader("Access-Control-Allow-Origin") == null)
                response.addHeader("Access-Control-Allow-Origin", "*");
            filterChain.doFilter(request, response);
        }
    
    }
    

    과:

    @Configuration
    public class RestConfig {
    
        @Bean
        public CORSFilter corsFilter() {
            CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            CorsConfiguration config = new CorsConfiguration();
            config.addAllowedOrigin("http://localhost:4200");
            config.addAllowedMethod(HttpMethod.DELETE);
            config.addAllowedMethod(HttpMethod.GET);
            config.addAllowedMethod(HttpMethod.OPTIONS);
            config.addAllowedMethod(HttpMethod.PUT);
            config.addAllowedMethod(HttpMethod.POST);
            ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**", config);
            return new CORSFilter(source);
        }
    }
    
  10. ==============================

    10.서버의 상태를 반환하는 메서드에 동일한 문제가있었습니다. 응용 프로그램은 여러 서버에 배포됩니다. 그래서 내가 찾은 가장 쉬운 방법은

    서버의 상태를 반환하는 메서드에 동일한 문제가있었습니다. 응용 프로그램은 여러 서버에 배포됩니다. 그래서 내가 찾은 가장 쉬운 방법은

    @CrossOrigin(origins = "*")
    @RequestMapping(value="/schedulerActive")
    public String isSchedulerActive(){
      //code goes here
    }
    

    이 메소드는 안전하지 않지만 allowCredentials를 추가 할 수 있습니다.

  11. from https://stackoverflow.com/questions/36968963/how-to-configure-cors-in-a-spring-boot-spring-security-application by cc-by-sa and MIT license