ABOUT ME

Today
Yesterday
Total
  • Spring Boot Web Application CORS Filter
    Spring Framework 2024. 1. 9. 17:41

    개요

    Spring Boot 로 Web Application 을 개발 했을 때 Client 가 Web Browser 일 수 있다.

    Client 가 웹 브라우저인 경우 Client 의 도메인과 Server(Spring Boot Web Application)의 도메인이 다르면 CORS 정책에 의해 에러가 발생한다.

     

    CORS 정책 위반 에러를 없이 Server(Spring Boot Web Application) 에서 다른 도메인의 Client 웹 브라우저의 요청을 처리 해 주기 위해서는 Server 에 CORS 를 허용하는 Filter 를 적용하면 된다.

     

    CORS 정책 에러

    에러 1 - No 'Access-Control-Allow-Origin' header is present on the requested resource

    웹 브라우저 도메인 "http://client.zzang.com:8080" 에서 Spring Boot Web Application 의 URL 을 post 로 호출 했을 때 CORS 정책에 위배 되었음을 알리는 에러

    from origin 'http://client.zzang.com:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

     

    에러 2 - Response to preflight request doesn't pass access control check

    • Content-Type이 application/json인 경우 실제 요청을 전송하기 전 OPTIONS 메서드를 이용하여 요청이 안전한지 확인 한다. => 사전 요청(Preflighted Request)
    • 사전 요청에 관해서는 204 No Content를 반환하는 것을 권장한다.

    request method OPTIONS 인 사전 요청에 대한 허용이 안 되어 있을 때 에러

    has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

     

    서버가 nginx 인 경우 사전 요청 허용 처리

    server {
        server_name api.zzang.com;
    
        location / {
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PATCH, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
                add_header 'Access-Control-Max-Age' 86400;
                return 204;
            }
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Content-Type' 'application/json' always;
            proxy_pass http://localhost:3000/;
        }
    
        listen 443 ssl;
        ssl_certificate /etc/letsencrypt/live/api.booklog.dev/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/api.booklog.dev/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }

     

    참고 : https://greeng00se.tistory.com/119

     

    [Nginx] CORS 설정

    개요 CORS 설정을 하지 않아서 배포한 웹 사이트에서 백엔드 API로 접근을 못하는 문제가 발생했습니다. 프론트 개발시에는 Vite를 이용하여 프록시를 설정하였고, 모든 요청이 프록시를 경유하도

    greeng00se.tistory.com

     

    에러 3 - The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed

    서버가 nginx 에서 revers proxy 로 Spring Web Applicaiton 으로 요청을 전달하는 서비스 구조인 경우 nginx 와 Spring Web Application 에 모두 CORS 허용 되어 있는 경우 에러

    Access to XMLHttpRequest at 'https://server.zzang.com/api' from origin 'https://client.zzang.com' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

     

    nginx 의 설정이나 Spring Web Application CORS 허용 Filter 중 하나만 사용한다.

    nginx 에서 CORS 설정을 사전 요청만 처리하고 reverse proxy 로 전달하지 않는 설정

    server {
        server_name api.zzang.com;
    
        location / {
            # 사전 요청만 nginx 에서 처리
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PATCH, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
                add_header 'Access-Control-Max-Age' 86400;
                return 204;
            }
            # 사전 요청 처리만 하고, proxy 로 전달 할 때는 CORS 처리 하지 않는다.
            #add_header 'Access-Control-Allow-Origin' '*' always;
            #add_header 'Content-Type' 'application/json' always;
            
            proxy_pass http://localhost:3000/;
        }
    
        listen 443 ssl;
        ssl_certificate /etc/letsencrypt/live/api.booklog.dev/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/api.booklog.dev/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }

     

    참고 : https://minholee93.tistory.com/entry/ERROR-The-Access-Control-Allow-Origin-header-contains-multiple-values

     

     

    Server CORS 허용 Filter

    Spring Boot Web Application 에서 Filter 를 구현하여 적용할 때 @Component 어노테이션을 사용하면 Spring Boot Web Application 이 Filter 를 적용 해 준다.

     

    Filter 구현을 위해서 servlet 클래스의 Filter 를 implement 해야 한다.

    package com.zzang.core.common.http.filter;
    
    import jakarta.servlet.*;
    import jakarta.servlet.http.HttpServletResponse;
    import org.springframework.http.HttpHeaders;
    import org.springframework.stereotype.Component;
    
    
    import java.io.IOException;
    
    @Component
    public class SimpleCORSFilter implements Filter {
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    
    		httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "OPTIONS, POST, GET");
    		httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
    		httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization,Device-info");
    		/*여기의 *을 내가 허용하고 싶은 특정 도메인으로 바꾸면 설정한 도메인에 한에서만 크로스 도메인을 허용하게된다. 여러 도메인의 경우 여러번 설정하면된다. */
    		httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
    
    		chain.doFilter(request, httpServletResponse);
    	}
    }
Designed by Tistory.