[사이드 프로젝트] 모아모아 사용자 정보 가져오기 with. 카카오 로그인

윤여준·2024년 1월 18일
0
post-thumbnail

배경

내가 현재 참여하고 있는 사이드 프로젝트 팀에서 어느 날 요구사항이 주어졌다.
바로 카카오 api를 사용하여 사용자 정보를 추출하라는 것이다.
먼저 팀에 합류하셨던 개발자님의 말을 들어보니 과거에 사용자 정보 추출을 시도하다가 테스트의 어려움 때문에 개발을 잠시 멈춘 상태라고 전해들었다.
카카오 로그인을 다루는 것은 처음이었는데, 일단 시작해봤다.

상황 파악

DB 확인

DB의 user 테이블을 우선 확인해보았다. 캡쳐를 해놓지 못해서 사진은 없는데, 그 당시의 기억을 살려보면 gender와 age_range 컬럼이 존재하긴 했었다. 하지만 그 컬럼들이 전부 null 값이었다.

사용자 정보의 범위

그러고선 우리 서비스에서 카카오 로그인을 통해 얻을 수 있는 정보가 무엇이 있는지 확인하기 위해서 카카오 디벨로퍼스의 내 어플리케이션 페이지를 들어가서 동의 항목을 확인하였다.

생일은 월과 일만 나오는 정보라서 의미가 없고 성별과 연령대를 제외한 항목은 동의를 설정할 수 있는 권한이 없었다. 그래서 의미 있는 사용자 정보 중에 가져올 수 있는 정보는 성별과 연령대가 전부라는 것을 확인했다.

테스트의 어려움 with. 프론트

기존의 카카오 로그인을 담당하던 코드의 일부분이다.

  public UserResponse.LoginDTO kakaoSimpleLogin(String code) throws Exception {
        String access_token = getKakaoAccessToken(code);
        HashMap<String, Object> kakaoUser = getKakaoUser(access_token);

        Optional<User> user = userJPARepository.findByEmail(kakaoUser.get("email").toString());
        if (user.isEmpty()) {
            UserRequest.KaKaoJoinDTO joinRequestDTO = new UserRequest.KaKaoJoinDTO(kakaoUser);
            kakaoJoin(joinRequestDTO);
	    public String getKakaoAccessToken(String code) {
        return access_token;
  }

kakaoSimpleLogin 함수의 매개변수에 code라는 String 변수가 있는 것을 확인할 수 있다.
이것 때문에 테스트가 어려워서 구현을 못하고 있었던 것이다.

위 그림은 카카오 공식 문서에서 제공하는 카카오 로그인 시퀀스 다이어그램 중 일부이다.
이 다이어그램을 보면 '인가 코드'라는 용어가 나온다. 인가 코드가 있어야 카카오 인증 서버로 토큰 발급을 요청할 수 있다.
kakaoSimpleLogin 함수의 code 매개변수가 바로 카카오 로그인에 사용되는 인가 코드이다.
우리 서비스는 이 인가 코드를 프론트엔드에서 받은 후에 백엔드로 넘겨주는 식으로 구현되어 있었던 것이다.
이 방법을 사용했을 때 카카오 로그인 자체를 구현하는 것은 전혀 문제가 없었다.
하지만 프론트 없이 백엔드 혼자서 테스트를 진행하려고 하니 문제가 생겼다. 프론트 없이는 인가 코드를 얻을 수 없기 때문이다. (여기서 말하는 테스트는 테스트 코드 작성이 아니라 직접 디버깅하는 것을 말한다..)
왜 이런 구조를 가지게 되었을지 지금 유추해보면, 프론트엔드 쪽 테스트의 수월성을 위해서 그랬을 것 같다. 프론트엔드에서 인가 코드를 받아야 백엔드 없이 토큰 발급 요청이 가능하기 때문이다.
반면 백엔드 쪽은 카카오 로그인 관련 수정 사항이 없어서 테스트할 필요가 없었고, 그래서 사용자 정보 추출 기능을 구현하기 전까지 별다른 문제를 느끼지 못했을 것 같다.

구현

우선 인가 코드 관련 문제는 프론트엔드 개발자에게 카카오 로그인 관련 프론트엔드 코드를 받고, 로컬에서 직접 실행시키는 방식으로 임시로 해결했다.
마음 같아서는 스프링 서버에서 직접 인가 코드를 받게 만들고 싶지만, 지금 카카오 로그인 관련 로직이 프론트엔드와 너무 결합되어 있어서 프론트엔드의 코드 수정이 불가피하다. 그래서 나 혼자서 리팩토링할 수 없었다. 추후 프론트엔드 쪽과 얘기할 기회가 생기면 리팩토링하려 한다.

구현 방법

프론트엔드에서 코드를 받고 로컬에서 실행시키는 것으로 테스트 문제를 임시로라도 해결하고 나니 그 후로는 수월하게 구현할 수 있었다.

public UserResponse.LoginDTO kakaoSimpleLogin(String code) throws Exception {
        String access_token = getKakaoAccessToken(code);
        KakaoUserInfoResponse kakaoUser = getKakaoUserByAccessToken(access_token);
        Optional<User> user = userJPARepository.findByEmail(kakaoUser.getEmail());

        if (user.isEmpty()) {
            UserRequest.KaKaoJoinDTO joinRequestDTO = new UserRequest.KaKaoJoinDTO(kakaoUser);
            kakaoJoin(joinRequestDTO);
        }
        UserRequest.KaKaoLoginDTO loginRequestDTO = new UserRequest.KaKaoLoginDTO(kakaoUser);
        UserResponse.LoginDTO responseDTO = kakaoLogin(loginRequestDTO);

        return responseDTO;
    }

우리 서비스의 카카오 로그인은 이 함수로부터 시작된다. 과정은 다음과 같다.
1. getKakaoAccessToken 함수를 호출하여 엑세스 토큰을 카카오 서버로부터 받아온다.
2. getKakaoUserByAccessToken 함수를 호출하여 카카오 유저 정보 객체를 가져온다.
3. 2번에서 가져온 카카오 유저 정보 객체의 이메일과 동일한 이메일이 서비스 DB의 user 테이블에 존재하는지 확인한다. (회원가입 여부 확인)
4. 만약 그러한 유저가 DB에 존재하지 않는다면 kakaoJoin 함수를 호출하여 회원가입한다. 이때 넘겨주는 joinRequestDTO에는 유저가 동의했을 경우에 생일과 연령대 정보가 담겨있다. 즉, 회원가입할 때 회원 정보를 저장하게 되는데, 이때 카카오에서 가져온 유저 정보도 함께 저장하게 된다.
5. 회원가입 과정이 끝나거나, 이미 회원가입이 되었다면 kakaoLogin 함수를 호출하여 로그인한다.

위 과정 중 4번에서 카카오 서버를 통해 얻은 유저 정보를 저장한다.

이미 회원가입된 사람들의 정보를 업데이트하기 위해 다음과 같은 함수도 admin 기능으로 만들었으나 이는 지금 일시적으로 사용하기 위해 만든 함수이기 때문에 설명은 생략한다.

자세한 코드는 아래의 관련 PR을 참고하길 바란다.

관련 PR

https://github.com/whatever-mentoring/PixelPioneers_BE/pull/13

  • 구현 관련 전체 코드는 PR 링크 확인

참고 자료

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
https://developers.kakao.com/docs/latest/ko/kakaologin/common

profile
Junior Backend Engineer

0개의 댓글