inflearn logo
강의

Course

Instructor

Spring Boot Security & JWT Lecture

[Google oauth2 관련] The dependencies of some of the beans in the application context form a cycle

897

dkfvktorco

5 asked

0

에러 메시지는 아래와 같습니다.

***************************
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

spring spring-security google oauth2

Answer 1

1

dkfvktorco

SecurityConfig에 있는 PasswordEncoder 생성자 코드를 Application.java로 옮겨주니 에러가 해결되었습니다!

0

qor0923

감사합니다. 덕분에 해결했습니다. 왜 해결됏는지 이유는모르겠지만..감사합니다

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

337

1

jwt와 실제데이터의 관계

1

241

1

jwt 와 세션ID의 관계

1

310

1

SecurityConfig에서 세션 설정, 인가 설정

0

415

1