될때까지

((WnB)) 5일차 : Kakao Social API 포스트맨 테스트 본문

프로젝트/wecode2차 : WnB

((WnB)) 5일차 : Kakao Social API 포스트맨 테스트

랖니 2022. 8. 5. 19:54
728x90

* 서버에 요청하는 메소드 : GET / POST

  1. GET방식 : URL뒤에 붙여서 보낸다.
    • ex)www.test.com?id=hello1&pw=abcd1234!
    • HTTP패킷의 '헤더'에 담긴다
  2. POST방식 : BODY에 데이터를 넣어서 보낸다.

 

* 헛짓(?)한 코드

import requests
import json
import jwt

from django.shortcuts   import redirect
from django.http        import JsonResponse
from django.views       import View

from users.models import User
from wnb          import settings

REST_API_KEY = 'b75ac57d41bd4ab6442b150d79e36bee'
REDIRECT_URI = 'http://127.0.0.1:8000/users/signup'
    
class KakaoSignUpView(View):
    def get(self, request):
        
        ###### 인가코드 요청하기 (나혼자)
        KAKAO_URL =f'https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}'

        code_data = {
            'grant_type' : 'authorization_code',
            'client_id' : REST_API_KEY,
            'redirect_uri' : REDIRECT_URI,
            'response_type' : 'code'
        }
        
        code_response = requests.get(KAKAO_URL, data=code_data)  # 요청에 대한 응답이 access_code에 담김
        
        code = request.GET.get('code')   # url에 /~~?code=1235로부터 code값 뽑아오기
        # print('코드', code)               # code뽑아오기 성공
        
        ###### 인가코드로 토큰 요청하기 (나혼자)
        KAKAO_URL_TOKEN = 'https://kauth.kakao.com/oauth/token' # 요청보낼 카카오 주소

        token_data = {
            'grant_type' : 'authorization_code',
            'client_id' : REST_API_KEY,
            'redirect_uri' : REDIRECT_URI,
            'code' : code
        }
        
        token_response = requests.post(KAKAO_URL_TOKEN, data=token_data).json()   # post로 보내라고 되어있음
        
        # print(token_response)                     # {}안에 필요한 값들이 담겨옴
        token = token_response.get('access_token')  # get을 사용하면 딕셔너리에서 벨류값 추출 가능
        # print('토큰', token)                         # 토큰 뽑아오기 성공

        ###### 토큰으로 유저정보 요청하기 (나혼자)
        KAKAO_USER_INFO = 'https://kapi.kakao.com/v2/user/me'
        HEADER          = {'Authorization' : f'Bearer {token}'}
        
        user_info_response = requests.get(KAKAO_USER_INFO, headers=HEADER).json()  
        
        kakao_id          = user_info_response['id']    # {} 딕셔너리에서 필요한 데이터값들 추출하기
        kakao_profile_img = user_info_response['kakao_account']['profile']['profile_image_url']
        email             = user_info_response['kakao_account']['email']
        # print(kakao_id, kakao_profile_img, email)       # 유저 데이터 뽑기 성공
        
        print('여기서에러')
        
        ###### kakao_id가 우리 DB에 있는 사람이라면 메인창으로 이동하기
        ## 에러발생 : 애초에 if문 안으로 못들어갈텐데 에러가 발생하고있음
        # if User.objects.get(kakao_id = kakao_id).exists():
        #     print('들어감')
        #     return redirect('https://www.naver.com')    # 이동시킬 메인화면 URL 적기
        
        # print('안들어감')
        
        ###### 우리 DB에 없는 사람이라면 추가정보 입력하는 창으로 이동하기
        return redirect(f'/users/info?kakao_id={kakao_id}')
    
class ExtraUserInfoView(View):
    def get(self, request):
    
        a = request.GET.get('kakao_id')   # def get, get하면 받을 수 있음.
        print(a)
        
    # ###### get -> post는 안되는데.. 이게 되나?? ㅠㅠㅠㅠㅠ    
    # def post(self, request):
    #     a = request.POST['kakao_id']
    #     print(a)
        
        # 사용자 정보를 추가 입력 받고
        # User 객체를 생성한다
        # User.objects.create(
#             first_name = first_name,          
#             last_name = last_name,      
#             email = email,         
#             kakao_id = kakao_id,      
#             kakao_profile_img = kakao_profile_img,
#             phone_number = phone_number,        
#             birth_day = birth_day
#         )

        # JWT토큰을 생성한다.
        # user_token = jwt.encode({'kakao_id' : a}, settings.SECRET_KEY, settings.ALGORITHM)
                
        # return JsonResponse({'result':'test'}, status=200)

내 하루가 사라졌다. 카카오 소셜 로그인을 사용하면 사용자의 이름/핸드폰번호/생년월일 등을 가져올 수 있다는 걸 분명히 확인했는데 내가 잘못알았다.. 이미 유저 모델링에는 사용자의 이름/핸드폰번호/생년월일이 필요한데 카카오 토큰으로부터 해당 정보들을 못가져오는 상황이였다.

이걸 어쩌지 어떻게 해야하나 멘토님께 여쭤보았더니, 새 창을 만들고 유저가 입력한 값을 받아서 저장하라고 하셨다!!

여기서 단순하게 아~~ 사용자가 입력받는 창으로 이동시켜야 하는구나 = uri이동이구나 = 구글링 후 redirect를 알아냈고 이걸 어떻게 써야하나 uri를 어떻게 만드나 하루를 꼬박 썼다. 더군다나 입력창으로 보내려면 post로 보내야하는데 카카오로부터 얻어낸 유저의 정보를 같이 담아서 전달이 가능한가..? 폭풍 구글링에도 원하는 결과를 얻지 못했고 결국 멘토님께 다시 헬프를 요청했다.

내 하루를 써버렸는데 멘토님께서 보시더니 화면이동은 백엔드가 관여할 일이 아니다. 프론트가 하는 일이라고 하셨다. 가만 생각해보니 당연한 말이지 왜 내가 그걸 하고앉아있었을까.. 빨리 해결하고 싶은 나머지 + 잠이 부족한 나머지 머리가 안돌아갔다.

허허허허 안녕 내 소중한 시간 즐거웠어 redirect야 그건 나중에 풀스택 때 다시 만나자 어쩐지 어렵더라 👋

그렇다면, 화면 이동은 프론트에서 담당한다. 나는 그럼 무엇을 해야할까? 

  1. 프론트엔드가 백엔드 서버로 카카오 토큰을 보내준다.
  2. 받은 카카오 토큰을 다시 카카오 서버로 요청을 보낸다.
  3. 카카오 서버가 유저 정보들을 담아 응답을 한다.
  4. 응답에서 필요한 정보들을 뽑아 유저 객체를 생성할건데,
  5. 우리 DB에 저장된 유저라면 '로그인 성공' 및 토큰을 발급한다.
  6. 우리 DB에 저장된 유저가 아니라면 DB에 저장하고 '회원가입 성공'을 보내준다.
  7. 회원가입 성공이 되면 추가 입력창으로 이동된다.
  8. 거기서 사용자가 입력하는 정보들은 또 다른 View를 만들어서 받아 업데이트 하면 된다.(Update)

 

위의 순서에 맞춰서 코드를 작성해봤다. 우선 1번부터 6번까지의 코드는 아래와 같다.

import requests
import json
import jwt

from django.http        import JsonResponse
from django.views       import View

from users.models       import User
from django.conf        import settings
    
class KakaoOauthView(View):
    def get(self, request):
    
        token = request.META.get('HTTP_AUTHORIZATION')   # 요청 헤더에 AUTHORIZATION으로 담겨옴
        
        KAKAO_URL = 'https://kapi.kakao.com/v2/user/me'
        HEADER 	  = {'Authorization': f'Bearer ${token}'}
        
        user_info = requests.get(KAKAO_URL,headers=HEADER).json()
        
        kakao_id          = user_info['id']    # {} 딕셔너리에서 필요한 데이터값들 추출하기
        kakao_profile_img = user_info['kakao_account']['profile']['profile_image_url']
        email             = user_info['kakao_account']['email']
        
        # kakao_id가 DB에 저장된 유저인지 먼저 확인하고 생성하기
        user, created = User.objects.get_or_create(
            kakao_id = kakao_id
        )
        
        if created:
            # created에 True가 담긴다면 => 없는 유저라서 생성했다면 그제서야 프로필이미지와 이메일을 저장해야한다.
            # 카카오 프로필 사진의 경우 유저가 변경할 수도 있어서 변하는 값이 된다.
            # kakao_id가 똑같아도 카카오 프로필 사진의 url이 다르면 다른 유저로 인식하니까 kakao_id로만 DB에서 찾자.
            user.kakao_profile_img = kakao_profile_img
            user.email             = email
            user.save()
            return JsonResponse({'message':'SIGNUP_SUCCESS'}, status=201)
        
        else:
            # 카카오id말고 고유값인 pk를 사용해서 토큰을 발급하자.
            token = jwt.encode({'id':user.id}, settings.SECRET_KEY, settings.ALGORITHM)
            return JsonResponse({'message':'SIGNIN_SUCCESS', 'token':token}, status=200)

 

토큰 발급을 처음에는 kakao_id를 사용했었다. 하지만 멘토님께서 나중의 확장성과 또 다른 소셜로그인이 있을 경우 id값이 겹칠일이 생길 수도 있다 하셨다. 이를 미연에 방지하기 위해서 토큰을 생성할때는 pk와 같은 고유값을 사용해서 토큰을 생성하는게 좋다!

kakao_id만으로 DB에 저장된 유저인지 아닌지 확인을 해야한다.(카카오 프로필사진은 url이 변경될 수도 있으니까) 확인 뒤 있다면 토큰을 발급해서 로그인을 시키고 없다면 유저에 생성하고 회원가입 환영합니다 201를 리턴해준다.

 

* 포스트맨으로 카카오 토큰받기 

1. Kakao Developers에 들어가서 앱키의 REST API키를 복사한다.

내 애플리케이션 > 앱 설정 > 앱키> REST API키

2. Redirect URI를 설정한다.

Redirect URI 설정하기 : https://getpostman.com/oauth2/callback

3. 포스트맨에서 필요한 값들을 입력한다.

포스트맨 설정방법

메소드 GET
URI https://kapi.kakao.com/v2/api/talk/memo/default/send 
Authorization Type OAuth 2.0
Token Name 마음대로 작성
Grant Type Authoization Code
Callback URL https://getpostman.com/oauth2/callback
Auth URL https://kauth.kakao.com/oauth/authorize
Access Token URL https://kauth.kakao.com/oauth/token
Client ID REST API키 복붙

4. 위처럼 값을 설정한 뒤에 주황색 버튼을 누르면 아래와 같이 access token을 얻을 수 있다.

token 받기 성공!

 

* 포스트맨으로 카카오 토큰을 이용해 유저정보 가져오기

1. GET메소드 / 주소 : https://kapi.kakao.com/v2/user/me  + Token에는 발급받은 토큰값 복붙한다.

2. Headers에서 아래 항목들을 체크한다.

3. send를 누르면 카카오에서 설정했던 동의 항목들에 대한 유저의 정보들만 조회된다.

혹시모르는 보안때문에 이름만 짤랐다

 

좋다..! get_or_create를 사용하니까 회원가입/로그인이 한번에 해결됐다. 이제 로그인 데코레이터를 작성해보자.

728x90