티스토리 뷰
세션 로그인 방식을 구현하고, 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()를 호출해 유저의 정보를 확인
스프링 시큐리티는 자기만의 시큐리티 세션이 존재한다.
시큐리티 세션에 들어갈 수 있는 객체 타입은 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();
}
}
'항해99(7기) > 항해 5주차' 카테고리의 다른 글
[항해99 7D]미니프로젝트 4일차 (0) | 2022.06.15 |
---|---|
[항해99 7D]미니프로젝트 3일차 (0) | 2022.06.14 |
[항해99 7D] 미니프로젝트 1일차 (0) | 2022.06.11 |