스프링 시큐리티 강좌를 보는데
순환 참조 에러가 발생했다....
(무한으로 사이클 돌려서 서로 참조)
SecurityConfig.class
@Configuration
@EnableWebSecurity // 스프링 시큐리티 필터가 스프링 필터 체인에 등록
@RequiredArgsConstructor
/**
* secured
* preAuthorize(postAuthorize)
* 메소드에 직접 권한 걸기 true
*/
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final PrincipalOauth2UserService principalOauth2UserService;
@Bean
public BCryptPasswordEncoder encoderPwd() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/user/**").authenticated() //인증만 받으면 접속 가능
// 인증뿐만 아니라, 권한도 있어야함
.antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.anyRequest().permitAll() //나머지 요청은 다 허용할게요
.and()
.formLogin()
.loginPage("/loginForm") // 로그인 페이지 명시
// .usernameParameter("id") // username 파라미터 이름 명시(기본 username)
.loginProcessingUrl("/login") //시큐리티가 대신 로그인 진행해줌(컨트롤러에 /login 안 만들어도 됨)
.defaultSuccessUrl("/") //로그인이 성공하면, 이 페이지로 가주세요
/**
* 1. 코드 받기(인증)
* 2. 액세스 토큰 받기(권한)
* 3. 사용자 프로필 정보 가져오기
* 4-1. 정보를 토대로 자동 회원가입
* 4-2. 추가 정보 필요하다면 작성
*/
/**
* 구글 로그인?
* 액세스 토큰 + 사용자 프로필 정보 한꺼번에 가져옴
* 코드 필요 X
* username = google_(sub)
* password = (암호화)겟인데어
* email = 구글이메일
* role = ROLE_USER
*/
.and()
.oauth2Login() //oauth2 로그인 허용
.loginPage("/loginForm") //구글 로그인 인증 페이지는?
.userInfoEndpoint() //로그인이 성공했다면?
.userService(principalOauth2UserService) //후처리 이렇게 해주세요
;
}
}
PrincipalOauth2UserService.class
@Slf4j
@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final UserRepository userRepository;
public PrincipalOauth2UserService(BCryptPasswordEncoder bCryptPasswordEncoder, UserRepository userRepository) {
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.userRepository = userRepository;
}
//로그인 후처리
// 구글로 받은 userRequest 데이터에 대한 후처리
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
log.info("userRequest = {}", userRequest);
// registrationId 로 어떤 OAuth 로 로그인했는지 확인 가능
log.info("getClientRegistration = {}", userRequest.getClientRegistration()); // 클라이언트가 누구니? (구글..)
log.info("getAccessToken = {}", userRequest.getAccessToken()); // 토큰(토큰 정보)
OAuth2User oAuth2User = super.loadUser(userRequest);
// 구글 로그인 버튼 클릭 -> 구글 로그인 창 -> 로그인 완료 -> code 리턴(OAuth - Client 라이브러리) -> AccessToken 요청
// userRequest 정보 -> loadUser() -> 구글로부터 회원 프로필 받아줌
log.info("getAttributes = {}", super.loadUser(userRequest).getAttributes()); // 유저 값(이름, 이메일...) // sub=115894611263003886842 -> primaryKey , 구글 회원 아이디 PK
// 회원 가입 강제 진행
String provider = userRequest.getClientRegistration().getClientId(); //google
String providerId = oAuth2User.getAttribute("sub");
String username = provider + "_" + providerId; // google_115894611263003886842
String password = bCryptPasswordEncoder.encode("겟인데어"); //의미는 없지만 그래도
String email = oAuth2User.getAttribute("email");
String role = "ROLE_USER";
User userEntity = userRepository.findByUsername(username);
// 찾은 userEntity가 없다며는 회워가입
if (userEntity == null) {
userEntity = User.builder()
.username(username)
.password(password)
.email(email)
.role(role)
.provider(provider)
.providerId(providerId)
.build();
userRepository.save(userEntity);
}
// Authentication 객체 안으로 들어감
return new PrincipalDetails(userEntity, oAuth2User.getAttributes());
}
}
┌─────┐
| securityConfig defined in file [\SecurityConfig.class]
↑ ↓
| principalOauth2UserService defined in file [C\PrincipalOauth2UserService.class]
└─────┘
SecurityConfig가 principalOauth2UserService 를 참조하고 있는데
principalOauth2UserService 에서는 BCryptPasswordEncoder 를 사용하려고 SecurityConfig 를 참조하고...
무한 반복으로 리사이클되는 에러 ㅡ.ㅡ.....
별거 다 해봤는데 이해를 잘 못하겠어서
기가맥힌 방법 알아냇다
@Bean
public static BCryptPasswordEncoder encoderPwd() {
return new BCryptPasswordEncoder();
}
걍 패스워드 인코더 빈 주입할 때 스태틱 메소드로 생성하믄 댄다
아마 객체 생성 전에 이미 클래스 영역에 만들어놔서
순환 참조 되지 않는듯...?(잘 모름)
글구 스태틱은 싱글톤이니께뭐..ㅎㅎ 굳이 빈 생성 안 해도 되지 않나?(잘 모름)
아시는 분들은 댓글로 좀 알려주세요..
728x90