ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 카카오 소셜 로그인 API - update_or_create()
    Django 2022. 1. 15. 17:38

     

    2차 프로젝트에서 카카오 로그인 API를 맡아서 진행하고 있습니다.

    카카오 소셜 로그인으로만 회원가입과 로그인이 가능하게 기획한 후에 코드를 짜기 시작했습니다.

     

    카카오 소셜 로그인의 전체적인 과정

     

    카카오로부터 전달받은 인증 코드를 프론트가 백에게 전달해주면 백에서 카카오에게 이 인증 코드를 보내고

    카카오가 유효성 검증 후에 이상이 없으면 토큰을 백에게 보내주고

    이 토큰을 백에서 우리 서버 전용 토큰으로 발급해서 프론트에게 전달해주는 과정입니다.

     

    사실 위에 그림은 Kakao Developers 문서에 있는 것인데 전체적인 과정을 이해하기에는 좋으나

    프론트와 백으로 나눠서 보기에는 다소 이해하기 어려운 부분이 있었습니다.

     

    아래의 글을 통해서 보다 쉽게 이해할 수 있었으니 참고 부탁드립니다.

    그래서 전체적인 과정부터 이해하신 후에 코드를 시작하셔야 그나마 삽질을 덜 할 수 있습니다..ㅠ

     

    https://data-jj.tistory.com/53

     

    REST-API 활용한 카카오 소셜 로그인 구현(feat. React)

    프로젝트를 진행하면서 소셜 로그인 구현을 맡게 되었다. 다들 프론트엔드는 소셜 로그인에서 할게 많이 없다 쉽다~, 그중에서 카카오가 가장 쉽다~ 이렇게 얘기해서 방심했다. 그렇게 6일간의

    data-jj.tistory.com

     

    import jwt
    import requests
    
    from django.http.response import JsonResponse
    from django.views         import View
    
    from bangguseok_traveller.settings import SECRET_KEY, ALGORITHM
    from users.models                  import User, UserType
    
    class LogInView(View):
        def get(self, request, user_type):	# user_type = 'Mentor'(1) or 'Mentee'(2) 선택
            try:
                print('request :', request)	# request가 어떤 식으로 오는지 확인하기 위해
                print()
                access_token    = request.headers.get('Authorization')
                print('access_token :', access_token)	# access_token 확인 용도
                print()
                profile_request = requests.get(
                    'https://kapi.kakao.com/v2/user/me', headers={'Authorization': f'Bearer {access_token}'},
                )
                print('profile_request :', profile_request)	# profile_request 확인 용도
                print()
                profile_json     = profile_request.json()
                kakao_properties = profile_json.get('properties')
                kakao_id         = profile_json.get('id')
                email            = profile_json.get('kakao_account').get('email')
                
                print('profile_json :', profile_json)	# profile_json 확인 용도
                print()
                print('kakao_properties :', kakao_properties)	# kakao_properties 확인 용도
                print()
                
                if not kakao_properties:
                    return JsonResponse({'message': 'ACCEPT_THE_TERMS_AND_CONDITIONS'}, status=400)
                
                nickname  = kakao_properties.get('nickname')
                user_type = UserType.objects.get(pk=user_type)
                    
                user, is_created = User.objects.update_or_create(
                    kakao_id = kakao_id,
                    defaults = {
                        'email'    : email,
                        'nickname' : nickname,
                        'user_type': user_type
                    }
                )
                token = jwt.encode({'kakao_id': user.kakao_id}, SECRET_KEY, ALGORITHM)
                print('token: ', token)	# token 확인 용도
                return JsonResponse({'token': token}, status=200)
            except UserType.DoesNotExist:
                return JsonResponse({'message': 'USERTYPE_DOESNOTEXIST'}, status=404)

     

    프론트에서 requests의 headers에 'Authorization' 키에 'access_token'을 담아서 보내주면

    그걸 'profile_request'라는 변수에 저장해둡니다.

     

    profile_request.json() 으로

    json 데이터를 dictionary 형태로 변환 후

    get을 통해서 필요한 값을 추출해서 변수에 담아둡니다.

     

    간혹 카카오로부터 오는 데이터 중에 'kakao_properties'가 없는 경우가 있어서

    if문을 통해서 프론트로 개인정보 동의에 관한 message를 전달하면 프론트 측에서 알림창을 띄워주기로 했습니다.

     

    kakao_id가 변하지 않는 값이라고 생각해서 kakao_id를 기준값으로 삼았습니다.

    처음에는 get_or_create 메소드를 통해서 DB에 kakao_id가 있으면

    해당 유저의 데이터를 가져와주고

    없다면  DB에 해당 유저의 데이터를 생성해줍니다.

     

    그렇지만 카카오의 nickname은 자주 변경할수도 있어서 변경 후에 다시 로그인을 한다면

    해당 유저의 nickname도 업데이트해주고 싶어서 update_or_create 메소드를 활용했습니다.

    get_or_create와 update_or_create 메소드가 거의 같은 방식으로 동작하기에

    하나를 이해하신다면 다른 것도 바로 이해하실 수 있을겁니다.

     

    1차 프로젝트 때 ZARA 웹사이트의 장바구니 앱에서 get_or_create 메소드를 사용했습니다.

    get을 사용하고 있어서 2개 이상의 값이 리턴되면 안되기에 DB에서 유일한 값일 kakao_id를 기준으로 했습니다.

    사용하면서도 defaults 부분이 이해가 잘 되지 않았는데 아래의 블로그를 통해서 확실하게 이해할 수 있었습니다.

    아래의 블로그에서 update_or_create 부분을 검색하셔서 보시는 것을 추천드립니다!

     

    https://blog.live2skull.kr/django/django-orm-01-basic/

     

    django - ORM 기본

    django ORM 개념 및 예제 모음입니다.

    blog.live2skull.kr

    defaults 값을 제외한 인자값으로 get()을 시도합니다.
    객체를 찾으면 **defaults 값으로 update()를 호출합니다.
    그렇지 않으면 인자값과 **defaults 로 새로운 인스턴스를 만들고 반환합니다.

     

    그 후 우리의 방식으로 인코딩한 토큰을 프론트에게 전달하여 유저에게 해당 토큰을 부여함으로써

    로그인이 필요한 경우에 매번 로그인하지 않고도 해당 서비스를 이용할 수 있게 했습니다.

     

    이 글을 쓰면서 jwt와 토큰에 대해서 잘 모르고 있다는 생각이 들었습니다.

    추후에 이에 대해 자세히 정리하여 글을 쓰고자 합니다.

     

     

     

     

     

     

    댓글

Designed by Tistory.