스프링 시큐리티 설정 파일 세팅 중 비밀번호 암호화 설정을 위해 PasswordEncoder 반환 타입의 메소드를 선언 하는 중 순환 참조 오류가 발생하였다.
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
순환 참조에 의존하는 것은 권장되지 않으며 기본적으로 금지되어 있습니다. Bean 간의 종속성 주기를 제거하도록 애플리케이션을 업데이트하십시오. 최후의 수단으로 spring.main.allow-circular-references를 true로 설정하여 자동으로 주기를 끊을 수 있습니다.
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'passwordEncoder': Requested bean is currently in creation: Is there an unresolvable circular reference?
bean 생성 오류: 요청된 bean이 현재 생성 중입니다: 확인할 수 없는 순환 참조가 있습니까?
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
...
http.rememberMe() // 사용자 저장
.rememberMeParameter("idMaintain") // default 파라미터는 remember-me
.tokenValiditySeconds(604800) // 7일로 설정(default 14일)
.alwaysRemember(false)
.userDetailsService(userDetailsService)
;
...
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
PasswordEncoder 반환 타입의 빈 생성 중 순환 참조가 발생하였다.
원인을 살펴보니 remember-me(자동 로그인) 에서 로그인 사용자의 정보를 저장하기 위해 사용되던 UserDetailsService 인터페이스를 의존성 주입하는 과정에서 passwordEncoder를 선언해 주는 부분이 있어 이 부분이 순환 참조가 발생한 것으로 보였다.
public class User implements UserDetails, CredentialsContainer {
...
@Deprecated
public static UserBuilder withDefaultPasswordEncoder() {
logger.warn("User.withDefaultPasswordEncoder() is considered unsafe for production "
+ "and is only intended for sample applications.");
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
return builder().passwordEncoder(encoder::encode);
}
...
}
몇시간 동안의 삽질 끝에 passwordEncoder 메서드를 정적(static)으로 선언하는 방식으로 해결..
정적 메서드는 표준 인스턴스화된 개체에서 벗아나 정적 메서드를 직접 호출하기 때문에 인스턴스화를 하지 않아 순환참조에서 벗어날 수 있었다.
@Bean
public static PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
알고보면 아주 간단한데 두시간을 날렸다 ㅜ
Reference
'Spring > Spring Security' 카테고리의 다른 글
[Spring Security] GET 로그아웃 처리 (0) | 2022.11.03 |
---|---|
[Spring Security] 스프링 시큐리티를 이용하여 로그인, 회원가입 구현하기 (0) | 2022.10.30 |
[Spring Security] Spring Security 설정하기 (0) | 2022.10.29 |
[Spring Security] 유저별 권한 설정 (0) | 2022.10.28 |
[Spring Security] 동시 로그인 제한하기(동시 세션 제어) (0) | 2022.10.28 |