본문 바로가기

백엔드/스프링(부트)

Spring Security와 Axios를 활용한 CORS 및 Authorization 헤더 문제 해결

반응형

문제 정의

1. CORS 문제

클라이언트와 서버가 다른 도메인에서 동작하는 경우, 브라우저 보안 정책에 의해 발생하는 CORS(Cross-Origin Resource Sharing) 문제가 발생할 수 있습니다. 이를 해결하지 않으면 클라이언트가 서버에 정상적으로 요청을 보낼 수 없습니다.

2. Authorization 헤더 비활성화 문제

클라이언트에서 서버로 요청을 보낸 후, 응답 헤더에 포함된 Authorization 값이 보이지 않아 undefined가 출력되는 문제가 발생했습니다.

// 로그인 함수
const loginUser = async (user: LoginUser): Promise<boolean> => {
  const id = toast.loading('로그인 중...');
  try {
    const formData = new FormData();
    formData.append('username', user.username);
    formData.append('password', user.password);

    const response = await client.post('/login', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      }
    });
    localStorage.setItem('Authorization', response.headers['authorization']); // undefined

  } catch (error) {
    console.error(error);
  }
};

 


문제 해결

1. CORS 문제 해결

Spring Security 6.4부터 CORS 설정 방식이 변경되었습니다. 따라서 최신 방식에 맞게 CORS 설정을 구성해야 합니다.

코드 수정

SecurityConfig 클래스에서 CORS 설정 추가

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors(cors -> cors.configurationSource(corsConfigurationSource()));

        // 기타 시큐리티 설정
        return http.build();
    }

    @Bean
    public UrlBasedCorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("http://localhost:5173")); // 허용할 출처
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE", "OPTIONS")); // 허용할 HTTP 메서드
        configuration.setAllowedHeaders(List.of("Authorization", "Content-Type")); // 허용할 헤더

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }
}

주요 설정 설명

  • setAllowedOrigins: 클라이언트 도메인을 지정합니다.
  • setAllowedMethods: 허용할 HTTP 메서드를 설정합니다.
  • setAllowedHeaders: 클라이언트가 요청 시 사용할 수 있는 헤더를 정의합니다.

2. Authorization 헤더 비활성화 문제 해결

CORS 설정에 추가적인 옵션이 필요합니다. 이를 통해 서버에서 응답 헤더를 클라이언트로 노출할 수 있도록 설정합니다.

코드 수정

SecurityConfig 클래스의 CORS 설정 수정

@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(List.of("http://localhost:5173"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(List.of("Authorization", "Content-Type")); // 허용할 헤더
    configuration.setAllowCredentials(true); // 서버 쿠키를 클라이언트에 설정할 수 있도록 허용
    configuration.addExposedHeader("Authorization"); // 클라이언트에 노출할 헤더 지정

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);

    return source;
}

주요 설정 추가 설명

  • setAllowCredentials(true): 서버에서 설정한 쿠키를 클라이언트가 받을 수 있도록 허용합니다.
  • addExposedHeader("Authorization"): 서버의 응답 헤더 중 Authorization 값을 클라이언트에서 접근 가능하도록 노출합니다.

최종 결과

클라이언트 측 코드

위의 서버 설정 이후, 클라이언트는 다음과 같이 응답에서 Authorization 헤더 값을 정상적으로 받을 수 있습니다.

const loginUser = async (user: LoginUser): Promise<boolean> => {
  const id = toast.loading('로그인 중...');
  try {
    const formData = new FormData();
    formData.append('username', user.username);
    formData.append('password', user.password);

    const response = await client.post('/login', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      withCredentials: true, // 쿠키를 포함하여 요청
    });

    // Authorization 헤더 값 저장
    localStorage.setItem('Authorization', response.headers['authorization']);

    return true;
  } catch (error) {
    console.error(error);
    return false;
  }
};

 

반응형