과정을 즐기자

자체 로그인, 소셜 로그인 같이 사용하기 본문

Spring

자체 로그인, 소셜 로그인 같이 사용하기

320Hwany 2023. 2. 11. 18:37

이번 글에서는 자체적으로 만든 로그인과 소셜 로그인을 같이 사용했던 방법에 대해서 정리하고자 합니다.

 

먼저 자체적으로 만든 로그인부터 살펴보겠습니다.

 

자체 로그인 구현

 

회원가입

입력한 정보를 바탕으로 DB에 저장하였습니다. 이때 비밀번호는 그대로 저장하면 보안상 문제가 

되기 때문에 BCyptPasswordEncoder를 사용하여 암호화 했습니다.  

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    
    ...
}

 

로그인,  로그아웃

 

먼저 입력한 정보가 DB에 있는 회원 정보와 일치하는지 확인한 후 로그인을 진행하는데 

로그인을 유지하기 위해 HttpSession을 이용하였습니다. 이때 member 엔티티에 대해서 세션을 생성하지 않고

MemberSession이라는 클래스를 따로 만들어서 이에 대한 세션을 형성하였습니다.

이유는 엔티티는 다른 엔티티와 관계가 있을 수 있기 때문에 아예 세션만 관리하는 MemberSession Dto를

따로 만들었습니다. 

 

다음으로 세션 정보는 톰캣과 같은 WAS에 저장하거나 MySQL 같은 DB에 저장하거나  Redis와 같은 

인메모리 DB에 저장할 수 있습니다. 이번에는 MySQL 같은 DB에 저장하는 방식으로 진행하였습니다.

 

여기서 MemberSession을 직렬화한 이유에 대한 설명을 우아한 형제들 기술 블로그에서 작성한 부분을 가져왔습니다.

  • 서블릿 세션 (Servlet Session)
    서블릿 기반의 WAS(톰캣, 웹로직 등)들은 대부분 세션의 자바 직렬화를 지원하고 있습니다.
    물론 단순히 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않지만,
    파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화가 되어 저장되어 전달됩니다.
    (그래서 세션에 필요한 객체는 java.io.Serializable 인터페이스를 구현(implements) 해두는 것을 추천합니다.)
    참고로 위 내용은 서블릿 스펙에서는 직접 기술한 내용이 아니기 때문에 구현한 WAS 마다 동작은 달라질 수 있습니다.
@Getter
public class MemberSession implements Serializable {

	...

    
   public void makeSession(HttpServletRequest httpServletRequest) {
        HttpSession session = httpServletRequest.getSession();
        session.setAttribute("memberSession", this);
   }
   
   public void invalidateSession(HttpServletRequest httpServletRequest) {
        HttpSession session = httpServletRequest.getSession(false);
        session.invalidate();
   }
}

 

MemberArgumentResolver 

다음으로 로그인이 필요한 API인 경우 ArgumentResolver와 @Login 에노테이션을 사용하여 로그인 정보를 

가져올 수 있도록 구현하였습니다.

@RequiredArgsConstructor
public class MemberArgumentResolver implements HandlerMethodArgumentResolver {

    private final MemberRepository memberRepository;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean hasMemberSessionType = parameter.getParameterType()
        					.equals(MemberSession.class);
        boolean hasLoginAnnotation = parameter.hasParameterAnnotation(Login.class);
        return hasMemberSessionType && hasLoginAnnotation;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, 
    				  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) 
                                  throws Exception {

        HttpServletRequest httpServletRequest = 
        			webRequest.getNativeRequest(HttpServletRequest.class);
        HttpSession session = httpServletRequest.getSession(false);
        if (session == null) {
            throw new MemberUnauthorizedException();
        }

        MemberSession memberSession = 
        			(MemberSession) session.getAttribute("memberSession");
        Member member = memberRepository.getById(memberSession.getId());
        return memberSession;
    }
}

 

소셜 로그인 구현

 

소셜 로그인 방식으로 카카오 로그인을 사용하였습니다. 이때 스프링 시큐리티를 사용하여 구현한 것이 아닌

카카오 로그인으로는 정보를 가져오고 자체적으로 회원가입, 로그인을 진행하였습니다.

 

 

카카오 로그인은 위와 같은 과정으로 진행됩니다. 이때 인가 코드를 받고 토큰을 받는 과정은 위와 같이 진행하였지만

OpenID Connnect를 사용하지 않고 발급 받은 토큰으로 사용자 정보를 조회하는 것까지만 사용하였습니다.

 

자세한 코드는 아래 링크를 참고해주세요

https://github.com/govldbstj/Mississipi/tree/backend/backend/src/main/java/com/backend/kakao

 

GitHub - govldbstj/Mississipi: 23 prometheus startup

23 prometheus startup. Contribute to govldbstj/Mississipi development by creating an account on GitHub.

github.com

 

이렇게 카카오 로그인으로부터 가져온 회원 정보가 이미 자체 서비스의 회원이면 그대로 로그인을 진행하고

회원이 아니라면 회원가입을 진행후 로그인을 진행하였습니다. 

이때 사용자 입장에서는 카카오 로그인만 하면 위와 같은 과정이 진행됩니다.

 

로그아웃도 마찬가지로 자체 로그인과 비슷하게 세션을 만료시켰지만 여기에 카카오 회원이라면

발급받은 accessToken으로 로그아웃을 요청하여 accessToken도 만료시켰습니다.

 

위와 같은 과정을 통해서 자체적으로 로그인을 하든 카카오로 로그인을 하였든 

다른 작업을 수행할 때 구분하지 않고 통합적으로 할 수 있게 되었습니다.

예를들어 회원정보를 수정하고자 한다면 두 로그인 방식 모두 @Login으로 회원정보를 가져올 수 있습니다.

 

Member  테이블

 

 

출처 : https://techblog.woowahan.com/2550/

 

자바 직렬화, 그것이 알고싶다. 훑어보기편 | 우아한형제들 기술블로그

{{item.name}} 자바의 직렬화 기술에 대한 대한 이야기입니다. 간단한 질문과 답변 형태로 자바 직렬화에 대한 간단한 설명과 직접 프로젝트를 진행하면서 겪은 경험에 대해 이야기해보려 합니다.

techblog.woowahan.com

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#before-you-begin

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com