카테고리 없음
Spring Security JWT 설정에서 DI 문제, 왜 신경 써야 할까? (직접 주입 vs Spring 관리)
w.llama
2025. 5. 8. 21:52
"코드가 돌아가는데 뭐가 문제냐고?"
지금 팀원이 작성한 코드를 코드리뷰하며 타 팀원이 지적한문제를 정리하고자 한다.
처음에 AuthenticationManager를 생성자 주입해서 쓸 때도 동작은 했어.
근데 이 방식은 Spring의 DI 원칙을 무시하는 꼼수였다. 차이점을 명확히 알자!
1. DI 원칙 위반 → 유지보수 문제
원본 코드 (문제점)
private final AuthenticationManager authenticationManager; //문제인 부분
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws
AuthenticationException {
... 생략
return authenticationManager.authenticate(token); //문제인 부분
}
- DI 원칙 위반 : Spring이 관리하는 빈을 수동으로 주입 받음.
- 순환 의존성 가능성 : SecurityConfig <-> LoginFilter 간 의존성 꼬임
- 테스트 불가능 : Mock 객체 주입이 매우 복잡해
개선 코드 (해결책)
//Spring이 관리하는 빈 사용
return this.getAuthenticationManager().authenticate(token);
- Spring 이 제공하는 기본 메커니즘을 사용
- 의존성 주입을 Spring에게 위임하여 설정을 간소화
이를 해결하기 위한 과정
1. LoginFilter에서 AuthenticationManager 제거
2. SecurityConfig 수정
//빈 등록필수
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// 기존 내용 없음
// 변경 LoginFilter 생성 (AuthenticationManager 주입 X)
LoginFilter loginFilter = new LoginFilter(jwtUtil, refreshRepository);
loginFilter.setAuthenticationManager(authenticationManager);
... 생략
// 기존
http.addFilterBefore(new JWTFilter(jwtUtil), LoginFilter.class)
.addFilterAt(new LoginFilter(jwtUtil, authenticationManager(authenticationConfiguration), refreshRepository),
UsernamePasswordAuthenticationFilter.class);
// 변경
http
.addFilterBefore(jwtFilter, LoginFilter.class)
.addFilterAt(loginFilter, UsernamePasswordAuthenticationFilter.class);
}
2. DI(의존성 주입)가 뭐길래?
간단 비유
"커피 머신이 커피콩을 직접 고르지 않고,
바리스타가 원두를 제공하는 방식"
핵심 개념
- 제어 역전(IoC): 객체 생성 주체가 개발자 → 프레임워크
- 장점: 코드 재사용성 ↑, 결합도 ↓, 테스트 용이성 ↑
현제 코드 적용 예
// Before: 직접 원두 선택 (의존성 강결합)
new LoginFilter(..., authenticationManager);
// After: 바리스타에게 맡김 (Spring DI)
this.getAuthenticationManager() // Spring이 알아서 주입
결론: DI는 선택이 아닌 필수다
"동작 한다 ≠ 좋은 코드"
- DI 원칙 준수 → 유지보수성 ↑, 확장성 ↑
- Spring 기능 최대 활용 → 생산성 ↑
- 테스트 편의성 → 버그 감소
처음엔 귀찮아 보여도 DI 원칙을 지키는 게 장기적으로 더 효율적으로 판단되었다.