프로젝트(개인)

애플리케이션 배포 시 마주친 문제와 해결책

그zi운아이 2024. 3. 27. 15:21

1. 인증 문제: Google OAuth2 403 Error

문제 상황

배포된 웹 애플리케이션에서 사용자가 Google 계정으로 로그인을 시도할 때, 403 Forbidden 에러가 발생했습니다.

 

원인 분석

  • 오류 참조 링크를 통해 에러 확인
  • Google OAuth2는 등록된 리다이렉션 URL로만 사용자를 리다이렉트하도록 엄격하게 제한합니다.
  • 개발 환경에서는 localhost로 설정된 리다이렉션 URL이 배포 환경의 URL과 다르기 때문에 인증 과정에서 문제가 발생했습니다.

해결 방법

  1. Google Cloud Console 접속: Google Cloud Platform에서 제공하는 프로젝트 대시보드에 로그인합니다.
  2. OAuth2 클라이언트 ID 설정: 인증 정보 섹션에서 OAuth2 클라이언트 ID를 선택하고, 리다이렉션 URL을 배포 환경에 맞게 업데이트합니다.
  3. 변경 사항 저장: 새로운 리다이렉션 URL을 추가한 후, 변경 사항을 저장하여 업데이트를 완료합니다.

이러한 변경을 통해, 배포 환경에서도 사용자가 Google 계정으로 안전하게 로그인할 수 있게 됩니다.

 


2. CORS(Cross-Origin Resource Sharing) 문제

문제 상황

웹 애플리케이션 개발 중, 클라이언트 애플리케이션이 서버로부터 데이터를 요청할 때 발생하는 보안 관련 문제입니다. 클라이언트와 서버가 다른 도메인에 있을 경우, 브라우저는 이를 크로스 오리진 요청으로 간주하고 보안 정책에 따라 요청을 차단할 수 있습니다.

원인 분석

웹 브라우저는 사용자를 보호하기 위해 동일 출처 정책(Same-Origin Policy)을 시행합니다. 이 정책은 웹 페이지가 다른 출처의 리소스를 불러오려 할 때 제한을 둡니다. 하지만 API 서버와 같은 경우, 다른 출처에서 오는 요청을 허용해야 할 필요가 있습니다. 이때 필요한 것이 CORS 정책입니다.

해결 방법

Spring Boot에서 CORS 문제를 해결하기 위해 WebMvcConfigurer 인터페이스를 구현하는 방법을 사용했습니다. 다음은 CORS 설정을 위한 구체적인 코드 예제입니다:

@Configuration
public class CorsConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins(
                            "로컬 링크",
                            "배포 링크")
                        .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE")
                        .allowedHeaders("*")
                        .allowCredentials(true);
            }
        };
    }
}

 

이 코드는 애플리케이션의 모든 경로(/**)에 대해 특정 출처(allowedOrigins)에서 오는 요청을 허용합니다. 또한, 모든 HTTP 메소드(allowedMethods)와 헤더(allowedHeaders)를 허용합니다.


3. SameSite 쿠키 설정 문제

문제 상황

최신 브라우저에서 SameSite 쿠키 정책의 기본값이 변경되면서, 다른 도메인으로부터 오는 요청에서 쿠키가 전송되지 않는 문제가 발생했습니다. 이로 인해, 사용자가 다른 사이트를 통해 로그인 상태를 유지하거나 API 요청을 할 때 인증 실패가 발생했습니다.

원인 분석

SameSite 쿠키 속성은 쿠키가 동일한 사이트의 요청에만 전송되어야 함을 브라우저에 지시합니다. SameSite=Lax가 기본값으로 설정됨에 따라, 타 사이트(크로스 사이트) 요청에서는 쿠키가 전송되지 않게 되었습니다. 이는 크로스 오리진 요청에서 인증 문제를 야기시켰습니다.

해결 방법

package com.example.fitconnect.config.web;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class SameSiteCookieFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        chain.doFilter(request, response);
        String cookies = response.getHeader("Set-Cookie");
        if (cookies != null) {
            response.setHeader("Set-Cookie", cookies + "; SameSite=None; Secure");
        }
    }
}

Spring Boot 백엔드 애플리케이션에 SameSiteCookieFilter 컴포넌트를 구현하여, 모든 Set-Cookie 헤더에 SameSite=None; Secure를 추가하도록 설정했습니다. 이 설정은 쿠키가 다른 사이트의 요청에도 전송될 수 있도록 하며, Secure 속성은 쿠키가 HTTPS를 통해서만 전송되도록 보장합니다. 또한, 이를 위해 AWS에서 제공하는 SSL/TLS 인증서를 사용하여 애플리케이션에 HTTPS를 적용했습니다.


4. 클라이언트-서버 라우팅 충돌

문제 상황

싱글 페이지 애플리케이션(SPA)을 개발할 때, 클라이언트 사이드 라우팅과 서버 사이드 라우팅 사이에 충돌이 발생할 수 있습니다. 사용자가 직접 URL을 입력하거나 페이지를 새로고침할 때, 서버가 해당 경로에 대한 페이지를 제공하지 못해 404 에러가 발생했습니다.

문제 상황

싱글 페이지 애플리케이션(SPA)을 개발할 때, 클라이언트 사이드 라우팅과 서버 사이드 라우팅 사이에 충돌이 발생할 수 있습니다. 사용자가 직접 URL을 입력하거나 페이지를 새로고침할 때, 서버가 해당 경로에 대한 페이지를 제공하지 못해 404 에러가 발생했습니다.

원인 분석

SPA에서 클라이언트 사이드 라우팅은 브라우저 내에서 페이지 간의 전환을 처리하지만, 사용자가 URL을 직접 입력하거나 새로고침을 하면 요청이 서버로 전달됩니다. 서버에는 SPA의 클라이언트 사이드 라우팅 정보가 없기 때문에, 해당 경로에 대한 리소스를 찾지 못하고 404 에러를 반환합니다.

로컬 개발 환경에서는 일반적으로 개발 서버의 프록시 기능을 사용하여 이 문제를 해결합니다. 프록시 설정을 통해 특정 API 경로에 대한 요청을 백엔드 서버로 전달함으로써, 개발 중에는 클라이언트와 서버 간의 요청이 원활하게 이루어집니다. 그러나 이 프록시 설정은 배포된 환경에서는 적용되지 않으며, 따라서 배포 환경에서는 다른 해결책이 필요합니다.

해결 방법

로컬 개발 환경에서의 프록시 설정을 배포 환경에 맞게 대체하고, 클라이언트-서버 라우팅 충돌 문제를 해결하기 위한 방안을 구현했습니다. 주요 해결 전략은 다음과 같습니다:

 

1. Axios 기본 URL 설정: 로컬 환경에서 사용되던 프록시 설정을 제거하고, axios의 인스턴스에 baseURL을 환경 변수를 통해 동적으로 할당했습니다. 이는 클라이언트 애플리케이션이 배포 환경에서 백엔드 서버와의 통신을 정확히 수행할 수 있게 합니다.

import axios from 'axios';

const axiosInstance = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL,
  withCredentials: true,
});

export default axiosInstance;

이렇게 설정함으로써, 배포 환경에서도 API 요청이 올바른 백엔드 서버로 전송되며, withCredentials 옵션을 통해 쿠키 기반 인증도 문제없이 동작하도록 보장합니다.

 

Spring Boot에서의 리다이렉션 설정: 클라이언트 사이드 라우팅과 서버 사이드 라우팅 충돌 문제를 해결하기 위해, 모든 요청을 index.html로 리다이렉션하는 Spring Boot 설정을 추가했습니다. 이 방식은 사용자가 웹 애플리케이션의 특정 경로에 직접 접근하거나 페이지를 새로고침할 때, 클라이언트 사이드 라우터가 해당 요청을 처리할 수 있게 해줍니다.

package com.example.fitconnect.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class WebController {

    @GetMapping(value = "/{path:[^\\.]*}")
    public String redirect() {
        return "forward:/index.html";
    }
}

 

이렇게 함으로써, 싱글 페이지 애플리케이션(SPA)의 경로가 클라이언트 사이드에서 제대로 처리될 수 있도록 합니다.