⭐️ 구현 코드는 맨 아래에 있다
access_token
을 받아온 이후 해당 유저 정보를 가져와 database에 저장Database
에 저장된 user
정보를 바탕으로 서비스(밥 먹언)의 자체적인 토큰을 발행json
의 객체 형태로 frontend에 전달mysql> desc users;
+-------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| created_at | datetime(6) | NO | | NULL | |
| updated_at | datetime(6) | NO | | NULL | |
| email | varchar(80) | YES | UNI | NULL | |
| password | varchar(200) | YES | | NULL | |
| nickname | varchar(80) | YES | | NULL | |
| profile_image_url | varchar(1000) | YES | | NULL | |
| date_of_birth | date | YES | | NULL | |
| platform_id | bigint | YES | MUL | NULL | |
+-------------------+---------------+------+-----+---------+----------------+
mysql> select * from platforms;
+----+---------------+-------------------+
| id | serial_number | social_network_id |
+----+---------------+-------------------+
| 1 | 2330177102 | 1 |
+----+---------------+-------------------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+----------------------------+----------------------------+-----------------+----------+----------+-------------------+---------------+-------------+
| id | created_at | updated_at | email | password | nickname | profile_image_url | date_of_birth | platform_id |
+----+----------------------------+----------------------------+-----------------+----------+----------+-------------------+---------------+-------------+
| 1 | YYYY:MM:DD HH:MM:SS.SSSSSS | YYYY:MM:DD HH:MM:SS.SSSSSS | ???@hanmail.net | NULL | ?? | http://~~~~ | NULL | 1 |
+----+----------------------------+----------------------------+-----------------+----------+------------------------------+---------------+-------------+
1 row in set (0.00 sec)
중요한 정보만 확대해 보았다.
mysql> select id, email, nickname, platform_id from users;
+----+-----------------+----------+-------------+
| id | email | nickname | platform_id |
+----+-----------------+----------+-------------+
| 1 | ???@hanmail.net | ?? | 1 |
+----+-----------------+----------+-------------+
아래처럼 platform
에서 create
로 해놓았다.
따라서 로그인을 할 때마다 새롭게 platform
의id
가 계속해서 생성된다.
kakao = SocialNetwork.objects.get(name='kakao').id
platform = Platform.objects.create(platform_id=kakao_id, social_network_id=kakao)
로그인 할 때마다 계속해서 platform_id
가 생성된다.
mysql> select * from platforms;
+----+-------------+-------------------+
| id | platform_id | social_network_id |
+----+-------------+-------------------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 2330177102 | 1 |
| 4 | 2330177102 | 1 |
+----+-------------+-------------------+
mysql> select * from platforms;
+----+-------------+-------------------+
| id | platform_id | social_network_id |
+----+-------------+-------------------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 2330177102 | 1 |
| 4 | 2330177102 | 1 |
| 5 | 2330177102 | 1 |
+----+-------------+-------------------+
mysql> select * from platforms;
+----+-------------+-------------------+
| id | platform_id | social_network_id |
+----+-------------+-------------------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 2330177102 | 1 |
| 4 | 2330177102 | 1 |
| 5 | 2330177102 | 1 |
| 6 | 2330177102 | 1 |
+----+-------------+-------------------+
platform_id
용어가 크게 두 가지라 혼동이 온다... 모델링을 수정해야 한다.create
대신에 get_or_create
써서 매번 create
를 하지 않고 이미 is_created
가 True
이면 get
을 해 오도록 바꾸었다.
kakao = SocialNetwork.objects.get(name='kakao').id
platform, is_created = Platform.objects.get_or_create(
platform_id = kakao_id,
social_network_id = kakao
)
platforms
의 platform_id
대신 serial number
로 수정하였다.
이제 계속 로그인 해도 없어지지 않는다
mysql> select * from platforms;
+----+---------------+-------------------+
| id | serial_number | social_network_id |
+----+---------------+-------------------+
| 1 | 2330177102 | 1 |
+----+---------------+-------------------+
import jwt, requests
from django.http import JsonResponse
from django.views import View
from django.conf import settings
from users.models import User, SocialNetwork, Platform
class KakaoSigninView(View):
def get(self, request):
try:
kakao_token = request.headers.get('Authorization')
KAKAO_URL = 'https://kapi.kakao.com/v2/user/me'
headers = {'Authorization': f'Bearer {kakao_token}'}
response = requests.get(KAKAO_URL, headers=headers, timeout=3)
kakao_user = response.json()
kakao_id = kakao_user['id']
kakao_nickname = kakao_user['kakao_account']['profile']['nickname']
kakao_email = kakao_user['kakao_account']['email']
profile_image_url = kakao_user['kakao_account']['profile']['profile_image_url']
kakao = SocialNetwork.objects.get(name='kakao').id
platform, is_created = Platform.objects.get_or_create(
serial_number = kakao_id,
social_network_id = kakao
)
platform, is_created = User.objects.get_or_create(
defaults = {
'platform_id' : platform.id,
'nickname' : kakao_nickname,
'email' : kakao_email,
'profile_image_url' : profile_image_url,
}
)
access_token = jwt.encode({'id': platform.id}, settings.SECRET_KEY, settings.ALGORITHM)
if is_created:
return JsonResponse({'message' : 'ACCOUNT_CREATED', 'access_token': access_token}, status=201)
else:
return JsonResponse({'message' : 'SIGN_IN_SUCCESS', 'access_token': access_token}, status=200)
except KeyError:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
get_or_create
로는 생성과 조회를 할 수는 있으나,get_or_create
의 한계점이 드러날 것이다.