본문 바로가기
TIL

StackOverflowError:null (feat.AuthenticationManager)

by Wanado 2025. 3. 7.
728x90

 

ERROR 30400 --- [auth-service] [io-19095-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause

java.lang.StackOverflowError: null

 

모놀리틱에서 msa로 전환을 시도해보았다.

 

 

모놀리틱에서는 잘되던 Authentication 필터에서 저 에러가 발생했다.

 

해결

https://kwakscoding.tistory.com/51

 

[스프링부트] 멀티인증 AuthenticationManager + Stackoverflow feat. UserDetailsService 무한재귀오류 해결

나는 REST-API용 로그인을 구축해놓은 상태에서 어드민 페이지를 추가로 만들어야 하는 상황이였다.보통 admin과 rest-api용 서버는 따로 나누지만 나같은경우 서버비용 절약 및 규모가 작은 프로젝

kwakscoding.tistory.com

 

근데 나는 반대로 UserDetailsService가 없어서 에러가 난 것이었다. 

 

 


🔍 Spring Security에서 AuthenticationManager가 하는 역할

1️⃣ AuthenticationManager는 Spring Security에서 사용자 인증을 담당하는 인터페이스

  • AuthenticationManager는 사용자의 인증 요청(아이디/비밀번호 로그인, JWT 토큰 인증 등)을 처리하고, 성공하면 Authentication 객체를 반환합니다.

2️⃣ 기본적으로 SecurityFilterChain이 AuthenticationManager를 자동으로 구성해야 하지만, Spring Boot 3 & Security 6에서는 기본 설정이 없음

  • 이전 버전(Spring Boot 2.x, Security 5.x)에서는 자동 설정이 포함되어 있어서 AuthenticationManager를 별도로 등록하지 않아도 동작했음.
  • 하지만 Spring Boot 3.x & Spring Security 6.x부터는 자동으로 AuthenticationManager를 등록하지 않기 때문에, 명시적으로 @Bean으로 등록해야 함.

코드 분석

  1. DaoAuthenticationProvider를 생성
    • DaoAuthenticationProvider는 Spring Security의 기본 인증 제공자로, UserDetailsService와 PasswordEncoder를 사용하여 아이디/비밀번호 인증을 수행합니다.
     
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailsService); provider.setPasswordEncoder(passwordEncoder());
    • provider.setUserDetailsService(userDetailsService); → UserDetailsServiceImpl을 이용해서 사용자 정보를 가져옴.
    • provider.setPasswordEncoder(passwordEncoder()); → 비밀번호를 암호화하고 비교할 PasswordEncoder를 설정.
  2. ProviderManager를 이용해 AuthenticationManager를 생성
    • ProviderManager는 여러 개의 AuthenticationProvider를 관리하는 Spring Security의 인증 관리자입니다.
    return new ProviderManager(provider);
    • 여기서는 DaoAuthenticationProvider 하나만 사용하지만, 필요하면 다른 AuthenticationProvider도 추가할 수 있음.
  3. Spring Security가 AuthenticationManager를 찾을 수 있도록 @Bean으로 등록
    • @Bean으로 등록하면 Spring Security가 AuthenticationManager를 주입받을 수 있기 때문에 authenticationManager must be specified 오류가 해결됨.
    •  

🔍 UserDetailsImpl과 UserDetailsServiceImpl의 역할 차이

✅ 1. UserDetailsImpl (사용자 정보 저장 및 관리)

  • Spring Security가 사용자 정보를 다룰 수 있도록 커스텀 UserDetails 구현체입니다.
  • 데이터베이스에서 가져온 사용자 정보를 Spring Security가 이해할 수 있는 객체로 변환하는 역할을 합니다.

✅ 2. UserDetailsServiceImpl (사용자 정보 조회 및 반환)

  • Spring Security에서 사용자 정보를 가져올 때 호출되는 UserDetailsService의 구현체입니다.
  • DB에서 username으로 사용자 정보를 조회하고, 조회된 정보를 UserDetailsImpl 객체로 변환하여 반환합니다.

 

더보기

Spring Security 인증 과정에서 UserDetailsImpl과 UserDetailsServiceImpl의 역할

1. 로그인 요청 (/auth/signIn)

  • 클라이언트가 username과 password를 입력하여 로그인 요청을 보냄.

2. JwtAuthenticationFilter가 요청을 가로챔

  • JwtAuthenticationFilter에서 authenticationManager.authenticate()를 호출.
  • UsernamePasswordAuthenticationToken을 생성하여 Spring Security의 AuthenticationManager에게 인증 요청.

3. AuthenticationManager가 UserDetailsServiceImpl.loadUserByUsername() 호출

  • UserDetailsServiceImpl이 username으로 사용자를 DB에서 조회.

4. UserDetailsImpl을 반환

  • 조회된 사용자 정보를 UserDetailsImpl 객체로 변환하여 반환.

5. 비밀번호 검증

  • DaoAuthenticationProvider가 입력된 비밀번호와 DB에서 가져온 비밀번호를 비교.

6. 인증 성공 시 SecurityContextHolder에 저장

  • SecurityContextHolder.getContext().setAuthentication(auth)를 호출하여 인증된 사용자 정보를 저장.
728x90