개요

현재 bizcowork에서 인턴으로 근무하고 있으며 서비스 개발 프로젝트에 참여하고 있다. 이번에 내가 맡게된 기능은 소셜 로그인과 연동 부분이다. 이 포스트에서는 소셜 로그인과 연동을 구현하고자 시도했던 것들을 자세히 기록하고자 이 포스트를 작성하게 되었다.


소셜 로그인

소셜 로그인으로는 카카오와 구글을 선택하였다. 우리나라에서 서비스를 하니 대부분의 한국사람은 카카오 또는 구글 둘 중에 하나는 사용하니 문제가 없을 듯하다. 소셜 로그인의 자세한 동작 구조를 보고 싶다면 소셜 로그인 동작 구조를 읽어보면 좀 더 이해하는데 도움이 될 듯 하다.


첫 번째 시행착오 - Django-allauth

현재 서비스는 프론트 엔드와 백엔드를 철저히 분리하여 개발을 하고 있으며 백엔드에서는 파이썬의 웹 프레임워크인 DRF를 사용하여 개발을 진행하고 있다. Oauth 프로토콜을 사용하는 라이브러리를 찾던 중 allauth가 적당하다고 생각하여 선택했다. allauth 말고도 몇가지의 라이브러리가 추가적으로 더 존재하지만 allauth는 많은 종류(네이버, 카카오 등)의 소셜 로그인을 지원하고 공급자(네이버, 카카오 등)가 제공하는 부정확한 정보를 로그인 과정에서 입력을 요구시킬 수 있도록 할 수 있어서 이 라이브러리를 선택하였다.

그러나 django-allauth를 이용해 소셜 로그인을 구현해보니 django session 값이 클라이언트 header에 저장되면서 로그인이 유지되는 방식이었다. 현재 서비스에서는 로그인시 knox 토큰 인증을 사용하고 있다. 나는 되도록이면 knox 토큰을 사용하도록 하고 싶었다. 그러나 django-allauth 라이브러리를 사용하면 초기 url만 설정해주면 자동적으로 url들이 생성되는 것이었다. 생성된 이 url 들은 restful api가 아니고 하나의 그냥 웹 그 자체였다. 그래서 지금 현재 개발하고 있는 방식과는 맞지 않아 이 방법을 철회하기로 마음먹었다.

추가적으로 django-allauth 라이브러리를 사용하게되면 상당히 많은 DB 테이블이 자동으로 만들어지게 되는데 거의 사용되지 않는 테이블이 있어서 비효율적이라 생각이 든다.

따라서 django-allauth는 프론트와 백엔드를 분리하여 개발할 때는 적합하지 않다!!!


두 번째 시행착오 - DB 테이블 설계 문제

소셜 로그인을 구현하면서 고려해야할 점이 있었다. API Key 문제인데 이 Key들을 setting에 명시해놓을지 아니면 DB에 저장해놓을지 결정하는 것이었다. 처음에는 DB에 저장하기로 생각하고 테이블을 설계하였다. 그러나 개발을 하면서 계속 보다 더 좋은 💡방안들이 자꾸 떠올랐다. 그래서 계속 테이블 구조를 변경하고 또 변경해서 거의 완성에 도달했다.

특히 소셜 연동 부분에서 테이블 변경이 많이 생겼는데 계정을 연동하는 기능은 이때까지 해본 것들 중에 처음하는 것이라 많이 해맸던 것 같다.

그렇게 완성한 테이블은 아래와 같다.

  • 처음에 설계한 테이블 구조는 여기에 테이블이 2개가 더 있었다. 그러나 계속 구현을 거듭하다보니 동작 구조가 이해가 되어서 최종적으로 위와 같이 테이블이 구성하게 되었다.
  • 위와 같이 테이블을 설계하면 소셜 회원가입/로그인은 물론 연동도 가능하다.


소셜 로그인 그 자체가 회원가입이고 연동이다.

위 제목이 바로 이해가 되지 않을 수도 있다. 그래서 한가지 예를 들어보겠다.

내가 처음 이용하는 서비스에 카카오 로그인을 하게되면 서버는 내부적으로 내가 쓰고 있는 카카오 계정의 정보를 바탕으로 회원가입을 거치게 된다. 그리고 이 계정은 카카오의 어디것과 연동되어 있다고 알 수 있게 되는 것이 socialuser 테이블의 social_user_id필드이다.

서비스를 이용하는 사용자 측면에서는 단순히 카카오를 통해 로그인되었다고 생각할 수 있지만 서버에서는 자동으로 회원가입을 시켜주면서 로그인을 가능하게끔 하는 것이다.



고심 끝에 완성한 소셜 로그인/연동 동작 구조

  • 동작 구조를 그림으로 만들어서 첨부하였다.

서비스 로그인 동작 순서

  1. 클라이언트는 카카오/구글 API 서버에 요청하여 access token을 발급받는다.
    • 토큰 관리는 클라이언트 측에서 합니다.
  2. 클라이언트에서 access_token을 서버로 전송한다.
  3. 클라이언트로부터 받은 access_token으로 카카오/구글 api를 호출해서 유효한 토큰인지 확인한다.
    • case 1 : 유효하지 않는 토큰인 경우 http 400 에러를 발생시킨다.
    • 토큰 시간이 100초 이상 남아있어야 다음 사항을 진행할 수 있다.
  4. 클라이언트로부터 받은 access_token으로 현재 카카오/구글에 로그인한 사용자 정보를 가져온다.
    • case 1 : 만약 카카오/구글 API에서 요청이 처리되지 않았을 경우 400 에러를 발생시킨다.
    • case 2 : (극히 드문일이겠지만) 트래픽이 많아서 서버가 지연되어 토큰이 만료가 되는 경우 400 에러를 발생시킨다.
  5. 카카오/구글에 로그인되어 있는 사용자 정보를 이용하여 회원 DB에 Insert 시킨다.
    • case 1 : 카카오/구글에서 관리되고 있는 회원 id를 이용하여 현재 연동되어 있는 계정이 있는지 확인한다.
      • 존재할시에 계정이 활성화되어 있으면 로그인 토큰을 발급한다.
      • 존재하지만 계정이 비활성화 상태이면 400 에러를 발생시킨다.
      • 존재하지않으면 회원가입을 진행한다.

글을 보면 여러가지 예외상황들이 존재해 좀 이해하기가 어려울 수 있다. 위 그림을 보면 한결 구조는 금방 이해가 될 것이다.


마치며

이번에 카카오/구글 api를 사용하면서 느낀점이지만 카카오 api가 정말 사용하기 쉽도록 문서화가 잘되어 있다는 것을 느낀다. 게다가 데브톡이라는 카카오 API를 사용하는데 있어서 정보를 공유할 수 있는 소통 공간도 있다.

그러나 구글 API는 문서가 참.. 난해하다. 내가 사용하고자 하는 API에 대해 가이드를 보고자 했는데 구글에서는 너무나 많은 API를 제공하고 있고 분류가 복잡하게 되어있다. 그래서 내가 쓰고자 하는 API가 어디 분류에 속해있는지 찾는데 시간을 꽤나 잡아먹었던 걸로 기억한다. 또 가이드 문서에 들어오면 왼쪽에 사이드바에 각 기능이 쓰여져 있고 그것을 누르면 바로 그 본문으로 이동된다. 그런데.. 왼쪽 사이드바에 명명해둔 이름 naming이 한글로 적혀있음에도 불구하고 “얘가 뭔일을 하는거야?”라는 의구심을 품게된다. 즉, 이름이 명확하지가 않다는 것이다.

다행히 구글링하여 다른 사람이 작성해둔 것을 보고 구현에는 성공적으로 마쳤지만.. 추후 다시 손댈 생각을 하니.. 겁이 난다.

카카오 API 문서는 사용자 친화적이다!