[Spring] 프로젝트와 소셜 로그인의 연동

[Spring] 프로젝트와 소셜 로그인의 연동

소셜 로그인 기능을 프로젝트에 적용해봅니다.


현재까지 작성한 프로젝트의 경우 소셜 로그인을 수행할 때 ClubAuthMember와 같은 객체를 사용하지 않는 상태입니다.
소셜 로그인 처리 시 사용자의 이메일 정보를 추출하고 현재 데이터베이스와 연동해 사용자 정보를 관리해야 합니다.
또한 기존 로그인 방식과 소셜 로그인 방식 모두 동일하게 동작하도록 만들어야 합니다.



1. ClubOAuth2UserDetailsService 생성



1

앞서 말한 작업을 수행하기 위해 OAuth2UserService를 알아야 합니다.
OAuth2UserService는 인터페이스로 UserDetailsService의 OAuth 버전이라고 생각할 수 있습니다. 이를 구현하는 것은 OAuth의 인증 결과를 처리한다는 의미입니다.
ClubOAuth2UserDetailsService는 DefaultOAuth2UserService를 상속받은 후 @Log4j2를 통해 동작 여부를 살펴볼 수 있도록 작성합니다. 또한 @Service를 작성해 스프링의 빈으로 자등으로 등록되게 합니다.
OAuth2UserRequest 타입의 userRequest로부터 정보를 추출해 스택 트레이스에 출력하며 oAuth2User로 컨버트 후 반환하도록 작성합니다.

2. ClubOAuth2UserDetailsService 생성 결과



2

프로젝트를 실행한 뒤 구글로 로그인을 진행할 경우 위의 그림과 같은 로그들이 출력되고 sub, picture, email, email_verified 항목이 출력되는 것을 확인할 수 있습니다.

3. ClubOAuth2UserDetailsService - saveSocialMember() 작성



3

OAuth2user를 이용해 로그인한 사용자의 이메일 주소를 알아낼 수 있고 이를 활용해 데이터베이스에 추가하는 작업을 수행할 수 있습니다. 이 때 임의로 패스워드를 지정해 데이터베이스에 저장할 경우 문제가 될 수 있습니다. 이는 조금 뒤에서 추가로 다루도록 하겠습니다.
데이터베이스에 저장을 위해 ClubMemberRepository와 PasswordEncoder를 주입받도록 @RequirredArgsConstructor를 사용하고 saveSocialMember()를 작성합니다.
eamil을 파라미터로 받아와 데이터베이스에 존재하는지 여부를 확인한 뒤 없는 경우에만 데이터베이스에 등록하도록 합니다.

4. ClubOAuth2UserDetailsService - saveSocialMember() 결과



4

saveSocialMember()를 작성한 뒤 소셜 로그인을 수행한 결과 구글 이메일 계정이 데이터베이스에 등록된 것을 확인할 수 있습니다.

5. ClubAuthMemberDTO 수정



5

DefaultOAuth2UserService()의 loadUser()의 경우 일반적인 로그인과는 다르게 OAuth2User 타입의 객체를 반환했습니다. 때문에 소셜 로그인을 진행한 후 member 화면을 살펴보면 이메일 주소가 아닌 사용자의 번호가 출력됩니다.
이를 해결하기 위해 OAuth2User 타입을 ClubAuthMemberDTO 타입으로 사용하도록 처리합니다.
ClubAuthMemberDTO는 OAuth2User의 인터페이스를 구현하도록 수정합니다. OAuth2User의 인증 결과는 attributes에 담겨있기 때문에 ClubAuthMember에 attr 변수를 만들어 getAttributes() 메소드를 override 합니다.

6. ClubOAuth2UserDetailsService - 리턴 타입 수정



6

loadUser()의 경우 oAuth2User를 반환하는 것이 아닌 oAuth2User에서 email만을 추출한 뒤 saveSocialMember()에서 나오는 결과를 사용해 ClubAuthMemberDTO를 생성하고 이를 반환하도록 수정합니다.

7. ClubOAuth2UserDetailsService - 리턴 타입 수정 결과



7

‘/sample/member’ 화면을 소셜 로그인 후 접근한 결과 정상적으로 이메일이 출력되는 것을 확인할 수 있습니다.
앞서 수행한 과정에서 생각할 부분이 있습니다. 소셜 로그인으로 데이터베이스에 등록한 회원의 경우 비밀번호가 모두 1111로 고정됩니다. 미리 설정해둔 fromSocial 값을 사용해 fromSocial 값이 false일 경우에만 로그인이 가능하도록 합니다.

8. ClubLoginSuccessHandler 생성



8

소셜 로그인을 한 사용자에 한해서 서브스에서 사용할 본인의 이름이나 패스워드를 수정하고자 한다면 로그인 이후에 폼 로그인과 달리 회원 정보를 수정할 수 있는 페이지로 이동할 필요가 있습니다.
스프링 시큐리티의 AuthenticationSuccessHandler를 사용해 인증이 성공하거나 실패한 후에 처리를 지정할 수 있습니다.
간단히 로그인 성공 이후의 결과를 살펴보기 위해 log가 출력되도록 작성합니다.

9. SecurityConfig - handler() 작성



9

작성한 ClubLoginSuccessHandler를 SecurityConfig에 @Bean으로 작성한 뒤 http의 formLogin()과 oauthLogin() 뒤에 succeessHandler()를 지정합니다.

10. SecurityConfig - handler() 작성 결과



10

‘sample/member’로 구글 로그인을 진행한 뒤 스택 트레이스를 확인해보면 정상적으로 ClubLoginSuccessHandler가 작동하는 것을 확인할 수 있습니다.

11. ClubLoginSuccessHandler - onAutheticationSuccess() 수정



11

로그인 후 redirect가 되도록 RedirectStrategy 인터페이스를 통해 구현할 수 있습니다. 이를 통해 소셜 로그인 회원은 회원 정보를 수정하도록 경로를 지정할 수 있습니다. RedirectStrategy 인터페이스는 구현 클래스인 DefaultRedirectStrategy 클래스를 사용해 처리하는데 소셜 로그인은 대상 URL을 다르게 지정하는 용도로 사용합니다
따라서 소셜 로그인 회원이면서 비밀번호가 1111일 경우 수정 페이지로 redirect가 되도록 코드를 작성해봅니다.
passwordEncoder를 주입해 비밀번호가 1111인지 확인하는 passwordResult와 fromSocial을 활용해 두 변수가 모드 True일 경우 RedirectStrategy를 활용해 회원 정보 수정페이지로 넘어가도록 합니다.

12. SecurityConfig - successHandler() 수정



12

ClubLoginSuccessHandler가 PasswordEncoder를 사용할 수 있도록 SecurityConfig의 @Bean을 수정합니다.

13. SecurityConfig - ClubLoginSuccessHandler 소셜 로그인 결과



13

‘sample/member’로 소셜 로그인한 결과 지정한 URL로 리다이렉트 되는 것을 확인할 수 있습니다.
수정 화면을 작성하지는 않았기 때문에 에러 화면만을 보게 됩니다.

14. SecurityConfig - rememberMe() 추가



14

스프링 시큐리티는 자동 로그인이라고 불리는 Remember me 기능을 제공합니다.
Remember me는 단순히 filterChain()의 http()에 rememberMe()를 지정한 뒤 유효 기간을 지정하는 tokenValiditySeconds()와 userDetailsService()를 지정하면 됩니다.

15. SecurityConfig - rememberMe() 추가 결과



15

로그인 화면에 Remember me 기능이 생긴 것을 확인할 수 있습니다.

16. SecurityConfig - rememberMe() 쿠키 확인



16

로그인 후 생긴 쿠키를 확인해보면 remeber-me 쿠키가 1주일간 유효하다고 나와있는 것을 확인할 수 있습니다.


© 2022. All rights reserved.