반응형
문제 정의
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;
}
};
반응형
'백엔드 > 스프링(부트)' 카테고리의 다른 글
스프링 시큐리티는 복잡합니다. 다만, 공통된 인증 흐름은 존재합니다. (0) | 2024.10.04 |
---|---|
[스프링 시큐리티] Refused to display 'http://localhost/' in a frame because it set 'X-Frame-Options' to 'deny' 에러 개선 (1) | 2024.09.18 |