티스토리 뷰

세션 로그인 방식을 구현하고, OAuth 방식으로 Google 로그인을 구현 시작했다.

 

login.html

html -> "/oauth2/authorization/google" 

OAuth Client 라이브러리에서 정해놓은 주소이기 때문에 주소를 지정해야함.

 

구글 로그인이 완료된 뒤의 후처리가 필요함.

1. 코드받기(인증)

2. 엑세스 토큰(권한) -> 코드가 아님, (엑세스 토큰 + 사용자 프로필 정보)

3. 사용자 정보 가져오기

4. 회원가입 자동 진행 / 추가적인 정보가 필요할 경우, 회원가입 창

 

WebSecurityConfig 의 SecurityFilterChain

.oauth2Login()
    .loginPage("/user/login")
    .userInfoEndpoint()
    .userService(googleUserDeatilsService)

OAuth2AuthenticationService를 상속받은 googleUserDetailsService는 super.loadUser 매서드를 통해 구글로부터 받은 userRequest 데이터에 대해 처리한다.

 

구글 로그인 버튼 클릭 -> 구글 로그인 창 -> 로그인 완료 ->Code Return(OAuth-Client 라이브러리) ->

AccessToken 요청 -> UserRequest 정보 -> 구글로부터 회원 프로필 받기(load User)

@Service
public class GoogleUserDeatilsServiceImpl extends DefaultOAuth2UserService {
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        return super.loadUser(userRequest);
    }
}

super.loadUser(userRequest)에는 구글 로그인 정보가 존재한다.

super.loadUser(userRequest).getAttribute()를 하면

{sub=1045779108, name=김민지, given_name=민지, family_name=김,

picture=https://lh3.googleusercontent.com/a/AATXAJxm5uiHv_J0zuVBQ6t1_fJfF_ixwEJo99Yxd-T1=s96-c, 

email=qwe123@gmail.com, email_verified=true, locale=ko}

와 같이 정보가 나타난다.

 

username = "google_1045779108"

password = 겟인데어(암호화)

email = "1045779108"

role = "ROLE_USER"

provider = "google"

providerId = 1045779108

 

로그인한 유저 확인 방법

  • Authentication 객체를 매개변수로 받아 .getPrincipal().getUser() 메소드로 로그인한 유저의 정보를 확인(UserDetails 객체)
  • @AuthenticationPrincipal 어노테이션을 활용해 UserDetails 객체를 implement 한 UserdetailsImpl 내의 메소드 .getUser()를 호출해 유저의 정보를 확인

-> 하지만 OAuth로 로그인한 로그인 유저들은 UserDetails 객체를 가지고 있지 않기 때문에 ClassCastException 오류가 발생함.

 

OAuth로 로그인한 유저 확인 방법

  • Authentication 객체를 매개변수로 받아 getPrincipal().getUser() 메소드로 로그인한 유저의 정보를 확인(OAuth2User객체)
  • @AuthenticationPrincipal 어노테이션을 활용해 OAuth2User내의 메소드 .getAttribute()를 호출해 유저의 정보를 확인

스프링 시큐리티는 자기만의 시큐리티 세션이 존재한다.

GoogleUserDetailsServiceImpl객체에 UserDetails/OAuth2User 객체 implement 하여 Authentication에 주입.

시큐리티 세션에 들어갈 수 있는 객체 타입은 Authentication 객체 뿐이다. Authenticaion 객체가 담을 수 있는 필드는 UserDetails와 OAuth2User이며 이를 따로따로 관리해주는 것이 아니라 UserDetails와 OAuth2User를 implements 하여 통합적으로 관리할 수 있는 PrincipalDetails 객체를 만든 후 Authentication에 저장한다.

 

PasswordEncoder의 순환참조 발생
@Configuration
@EnableWebSecurity //스프링 시큐리티가 필터체인에 등록됨
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {
    @Autowired
    private GoogleUserDeatilsServiceImpl googleUserDeatilsService;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
    	return BcryptPasswordEncoder();
    }
    ...
@Service
@RequiredArgsConstructor
public class GoogleUserDeatilsServiceImpl extends DefaultOAuth2UserService {
    private final PasswordEncoder passwordEncoder;
    ...

WebSecurityConfig에서 GoogleUserDetailsServiceImpl을 DI 시켜주는데, WebSecurityConfig에서 @Bean을 선언한 PasswordEncoder을 받아와야해서 Bean의 생성 순서 문제에 의해 순환참조가 발생했다.

GoogleUserDetailsServiceImpl → WebSecurityConfig → WebMvcConfig → UserArgumentResolver → GoogleUserDetailsServiceImpl ...

WebSecurityConfig에서 선언한 PasswordEncoder를 따로 빼주어 완료했다.

@Configuration
public class Encoder {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함