[Google oauth2 관련] The dependencies of some of the beans in the application context form a cycle
897
5 asked
에러 메시지는 아래와 같습니다.
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| oauth2UserService defined in file [D:\GooGoo\out\production\classes\eunhye\GooGoo\config\oauth\Oauth2UserService.class]
↑ ↓
| securityConfig defined in file [D:\GooGoo\out\production\classes\eunhye\GooGoo\config\security\SecurityConfig.class]
└─────┘
Action:
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.
Process finished with exit code 1
oauth2UserService와 securityConfig가 cycle을 이루고 있다.
뭔가 구조가 잘못됐다는 것을 알 수 있었습니다만...
전 강의 잘 듣고 잘 코드 쳤다고 생각이 되거든요ㅠ
스스로를 의심하며 아무리 코드를 쳐다봐도 잘못된 점을 모르겠어서 질문 올립니다.
다음은 관련된 코드들입니다.
Oauth2UserService.java
package eunhye.GooGoo.config.oauth;
import eunhye.GooGoo.config.security.SecurityDetails;
import eunhye.GooGoo.dto.UserDTO;
import eunhye.GooGoo.entity.UserEntity;
import eunhye.GooGoo.entity.UserRole;
import eunhye.GooGoo.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class Oauth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
// 구글로부터 받은 userRequest 데이터에 대해 후처리하는 함수
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException{
OAuth2User oauth2User = super.loadUser(userRequest);
// 회원가입 강제 진행
String provider = userRequest.getClientRegistration().getClientId();
String providerId = oauth2User.getAttribute("sub");
String userNickname = provider+"_"+providerId;
String userEmail = oauth2User.getAttribute("email");
String userPassword = passwordEncoder.encode("겟인데어");
UserRole authority = UserRole.USER;
UserEntity userEntity = userRepository.findByUserEmail(userEmail);
if(userEntity == null){
userEntity = UserEntity.builder()
.userNickname(userNickname)
.userEmail(userEmail)
.userPassword(userPassword)
.authority(authority)
.provider(provider)
.providerId(providerId)
.build();
userRepository.save(userEntity);
}
return new SecurityDetails(userEntity, oauth2User.getAttributes());
}
}
SecurityConfig.java
package eunhye.GooGoo.config.security;
import eunhye.GooGoo.config.oauth.Oauth2UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig{
private final AuthenticationFailureHandler customFailureHandler;
private final Oauth2UserService oauth2UserService;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/user/**").authenticated()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home")
.usernameParameter("userEmail").passwordParameter("userPassword")
.failureHandler(customFailureHandler)
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login")
.and().oauth2Login()
.loginPage("/login").defaultSuccessUrl("/home")
.userInfoEndpoint().userService(oauth2UserService);
return http.build();
}
}
SecurityDetails.java
package eunhye.GooGoo.config.security;
import eunhye.GooGoo.entity.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
@Data
public class SecurityDetails implements UserDetails, OAuth2User {
// 일반 로그인
private final UserEntity userEntity;
// OAuth 로그인 (Google)
private Map<String, Object> attributes;
public SecurityDetails(UserEntity userEntity){
this.userEntity = userEntity;
}
public SecurityDetails(UserEntity userEntity, Map<String, Object> attributes){
this.userEntity = userEntity;
this.attributes = attributes;
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public String getName() {
return userEntity.getId()+"";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return userEntity.getAuthority().toString();
}
});
return authorities;
}
@Override
public String getPassword() {
return userEntity.getUserPassword();
}
@Override
public String getUsername() {
return userEntity.getUserEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
추가적인 코드가 필요하다면 아래 깃헙 링크 참고해주세요
https://github.com/you-eun-hye/GooGoo
Answer 1
1
SecurityConfig에 있는 PasswordEncoder 생성자 코드를 Application.java로 옮겨주니 에러가 해결되었습니다!
JWT를 구현한 다음 이 API를 호출해서 사용하는 것은 프론트엔드 쪽에서 하는 역할인가요?
0
94
1
Jwt쓰면 스프링시큐리티는 필수적으로 사용해야하나요?
0
401
1
13:23 system.out 출력문이 다르게 나옵니다.
0
129
1
수료증 문의
0
226
2
9분대에 질문이 있습니다 !
0
114
1
password 비교를 하지 않았는데 어떻게 인증이 통과된 건가요?
0
320
1
이전 강의 참고하라는 말씀
0
253
1
강의 실습하다가 막히는 분들 참고(2024년8월 기준)
2
1116
2
구글 소셜 로그인 302
0
200
1
오류 문의 _ org.springframework.orm.jpa.JpaSystemException: could not deserialize
1
584
1
[자바] 시큐리티 Config 참고
13
953
1
이론강의
0
280
1
SpringSecurity JWT 로그인 URL 2개 설정하는 방법
0
486
1
2024.06기준) 최근 SecurityConfig 설정 문의
0
921
3
구글 로그인시 authentication이 null 값이라고 에러가 발생합니다.
0
677
2
특정 url필터 거는 방법 이슈
0
422
1
강사님께서 말씀하시는 시큐리티세션이 SecurityContext인가요?
0
277
1
25강 마지막 테스트에서 오류
1
1044
2
jwt를 저장하는 위치에 궁금한 점이 있습니다.
0
298
1
mustache를 사용하지 않고 thymeleaf를 사용하려고 하는데
0
694
1
세션 인증방식이 REST 원칙에 위배되는 건가요?
0
336
1
jwt와 실제데이터의 관계
1
241
1
jwt 와 세션ID의 관계
1
310
1
SecurityConfig에서 세션 설정, 인가 설정
0
415
1

