TIL[79].소셜 로그인_카카오

jake.log·2020년 10월 18일
0

1. 소셜로그인이란?

웹에서 다른 서비스의 계정을 빌려 새로운 계정을 만들거나 로그인 하는 것을 말한다.

구글, 페이스북, 네이버, 카카오, 깃허브 등의 뿌리계정을 통해 로그인이 가능하도록 하여 서비스 이용자 입장에서 시간 단축 등의 장점을 준다. 서비스 제공자 입장에서는 번거로운 가입 과정을 줄여줄 수 있어 소비자 이탈을 막을 수 있다. 물론 소셜 계정을 탈퇴하거나 해킹을 당할 경우 서비스를 이용할 수 없는 단점도 존재하지만, 최근 많은 웹사이트에서 클라이언트들이 서비스에 편하게 접근할 수 있도록 소셜 로그인 기능을 적용한다.

2. 카카오 로그인 적용 과정

그렇다면 소셜 로그인 기능은 어떤 원리로 작동 될까?

카카오를 예로 들어보자.

카카오 로그인은 카카오 계정과 애플리케이션으 연결하여 토큰을 발급 받고 카카오 API 를 사용할 수 있도록 하는 기능이다.

[참고: https://developers.kakao.com/docs/latest/ko/kakaologin/common]

  1. 우선 적용하고자 하는 웹사이트 애플리케이션을 kakaoDevelopers에 등록하면 고유 API키를 발급받게된다.

  2. 프론트엔드에서 로그인 버튼을 누르면 사용자 동의를 얻고 토큰을 얻을 수 있도록 해당 키를 통해 인증코드를 호출 하고 전달 받는다.

  3. 이후 전달 받은 인증 코드로 카카오 서버에 토큰을 요청하면 카카오서버에서 카카오 사용자의 토큰(Access Token, Refresh Token)을 전달해준다.

  4. 프론트엔드에서 받은 카카오 사용자 토큰을 백엔드에게 보내주면, 백엔드에서는 해당 토큰을 받아 카카오에 사용자 정보과 관련된 API를 호출한다.

  5. 카카오 서버에서는 토큰이 맞는지 확인하고 사용자 정보를 보내준다.

  6. 사용자 정보를 얻게되면 백엔드에서 사용자 정보가 데이터베이스에 있는지 확인하고, 존재하면 토큰을 발행하여 로그인을 시킨다.

  7. 새로운 사용자 정보일 경우 user 정보는 새롭게 만들어지고 토큰이 발행 된다.

3.작성 코드

아래의 작성 코드는 위 적용 과정의 4번부터 7번까지의 과정을 코드로 작성한 것으로, 프론트에서 post로 보내준 token을 통해 백엔드에서 카카오 API에 필요한 사용자 정보를 호출하고 로그인 되는 과정이다.

views.py

class KakaoSignInView(View):    
    def post(self,request):
        try: 
            access_token   = request.headers.get('Authorization')
            url            = 'https://kapi.kakao.com/v2/user/me'
            headers        = {'Authorization':f'Bearer {access_token}'}
            kakao_response = requests.get(url, headers=headers).json()
            kakao_id       = kakao_response.get('id')
            kakao_account  = kakao_response.get('kakao_account') 
            email          = kakao_account.get('email',None)
            kakao_profile  = kakao_account.get('profile')
            name           = kakao_profile.get('nickname')
        
            if Account.objects.filter(email=email).exists():
                user  = Account.objects.get(email=email)
                token = jwt.encode({'id':user.id},SECRET,algorithm=ALGORITHM)
                token = token.decode('utf-8')
                
                return JsonResponse(
                    {'token'  : token,
                    'message' : 'SUCCESS'}, 
                    status=200
                )
        
            else:
                Account.objects.create(
                    kakao_id = kakao_id,
                    email = email,
                    name = name
                )              

                token = jwt.encode({'email':email},SECRET,algorithm=ALGORITHM)
                token = token.decode('utf-8')
                
                return JsonResponse(
                    {'token'  : token,
                    'message' : 'SUCCESS'}, 
                    status=200
                )
        
        except IntegrityError:
                    return JsonResponse(
                        {'message':'ALREADY_EXISTS'},
                        status = 400 
                    )

        except KeyError:
            return JsonResponse({'message':'KEY_ERROR'},status = 400)      

tests.py

class KakaoSignInTest(TestCase):
    
    def setUp(self):
        Account.objects.create(
            kakao_id = '1499',
            name     = 'hong',
            email    = 'hong@gmail.com',
        ) 
    def teardown(self):
        Account.objects.all.delete()
    
    @patch('account.views.requests')
    def test_kakao_sign_in(self,mocked_requests):
        client = Client()
        
        class MockedResponse:
            def json(self):
                return{
                    'id'      : 1499, 
                    'kakao_account': { 
                    'profile': {
                        'nickname': 'hong',
                    },'email': 'hong@gmail.com'}
                }
                           
        mocked_requests.get = MagicMock(return_value = MockedResponse())
        
        test = {
            'kakao_id' : 1499, 
            'email'    : 'hong@gmail.com',
            'name'     : 'hong',
            }

        response = client.post('/account/emailcheck/kakaosignin',json.dumps(test), **{'Authorization':'1234', 'content_type':'application/json'})
        self.assertEqual(response.status_code,200)
profile
꾸준히!

0개의 댓글