Spring Framework

Spring Boot Web Application CORS Filter

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