📝 개요
✅ To-Do
마이페이지
전체 메뉴
📸 스크린샷
마이페이지 (/mypage)
- 회원 정보 조회/표시, 프로필사진 수정, 회원 정보 (이름, 비밀번호)수정, 회원 탈퇴
전체 메뉴 (/mainMenu)
Trouble Shooting
CORS 설정
- 문제: 회원정보 변경 요청 시, 이름/비밀번호는 CORS 통과 되는데 프로필사진 변경은 CORS에 걸림
-
원인:
- 파일 업로드 요청에서만 CORS가 막히는 이유는
multipart/form-data 요청과 Spring Security 필터 체인의 처리 순서에 있음
-
설명:
- 파일 업로드 요청의 특성:
multipart/form-data는 일반 JSON 요청과 다른 Content-Type을 가짐
- Spring Security 필터 순서: CORS 필터가 Security 필터 체인에서 부적절한 위치에 있을 수 있음
- OPTIONS 요청 처리: 브라우저가 파일 업로드 전에 보내는
preflight OPTIONS 요청이 제대로 처리되지 않을 수 있음
-
해결 방법:
CorsConfigurationSource 분리: CORS 설정을 별도 Bean으로 분리하여 더 명확하게 관리
- 헤더 명시적 설정:
multipart/form-data 요청에 필요한 헤더들을 명시적으로 허용
OPTIONS 요청 강화: 모든 경로에서 OPTIONS 요청을 허용하도록 변경
- 필터 순서 명시: CORS 필터를 명시적으로 필터 체인에 추가
preflight 캐시: maxAge 설정으로 preflight 요청 최적화
package com.lighthouse.security.config;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
@Slf4j
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = {"com.lighthouse.security"})
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${FRONT_ORIGIN}")
private String frontOrigin;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedOrigin(frontOrigin);
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
// multipart/form-data 요청을 위한 추가 설정 - 프로필사진 업로드 시 사용
configuration.setAllowedHeaders(Arrays.asList(
"Authorization", "Content-Type", "Content-Disposition", "Content-Length",
"X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
"Access-Control-Request-Headers"
));
configuration.setExposedHeaders(Arrays.asList(
"Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"
));
configuration.setMaxAge(3600L); // preflight 캐시 시간 설정 (1시간)
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public CorsFilter corsFilter() {
return new CorsFilter(corsConfigurationSource());
}
// 접근 제한 무시 경로 설정 – resource
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/assets/**", "/*", "/api/member/**",
"/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/api-docs");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable()
.csrf().disable()
.formLogin().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.cors().configurationSource(corsConfigurationSource()); // CorsConfigurationSource 명시적 지정
http
.authorizeRequests() // 경로별 접근 권한 설정
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 모든 OPTIONS 요청 허용
.antMatchers(HttpMethod.PUT, "/api/member").authenticated()
.anyRequest().permitAll();
}
}
📝 개요
✅ To-Do
마이페이지
전체 메뉴
📸 스크린샷
마이페이지 (/mypage)
전체 메뉴 (/mainMenu)
Trouble Shooting
CORS 설정
원인:
multipart/form-data요청과 Spring Security 필터 체인의 처리 순서에 있음설명:
multipart/form-data는 일반 JSON 요청과 다른Content-Type을 가짐preflight OPTIONS요청이 제대로 처리되지 않을 수 있음해결 방법:
CorsConfigurationSource분리: CORS 설정을 별도 Bean으로 분리하여 더 명확하게 관리multipart/form-data요청에 필요한 헤더들을 명시적으로 허용OPTIONS요청 강화: 모든 경로에서 OPTIONS 요청을 허용하도록 변경preflight캐시:maxAge설정으로 preflight 요청 최적화