[TIL] # 41 소셜 로그인

ddalkigum·2021년 1월 30일
3

TIL

목록 보기
40/50
post-thumbnail
post-custom-banner

Oauth2

Oauth란 사용자들의 비밀번호를 제공하지 않고
다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 어플리케이션의
접근 권한을 부여할 수 있는 공통적인 수단으로 사용되는 서비스

access_token을 이용하여 유저를 확인하고, 이를 통해
최소한의 유저 정보를 제공해준다

Oauth를 통해 인증이 이루어 지기 위해서는 4가지가 필요한데

자원 소유자

어플리케이션을 이용하는 유저

자원 서버

유저의 정보를 보관하고 있는 서버

client

유저가 사용하려는 어플리케이션

인가 서버

유저를 인증하고, client에게 access_token을 발행해 주는 서버

4가지가 필요하고, 자원 서버는 소셜로그인을 제공해주는
구글, 깃허브, 구글, 카카오 등의 인증된 서버를 의미한다

Token

Access_token, Refresh_token 총 2가지로 발급이 되는데

Access_token은 인가 서버에서 발급받은 토큰으로, 유저를 확인하는 매개체로 사용된다
이 토큰의 경우, 유효기간이 일주일정도로 짧기 때문에 refresh_token을 이용하려
access_token을 재발급받는 방식으로 유지한다

Refresh_token은 Access_token의 유효기간이 만료된 경우
Access_token을 재발급받기 위한 용도로 사용된다

매번 Access_token을 발급받는 다는건 그만큼의 손실을 의미하기 때문에
Refresh_token을 사용한다

kakao_login

카카오 소셜 로그인은 Oauth2 방식을 사용하여 발급받게 되고,
이를 이용해 유저의 최소한의 개인정보를 제공받아 DB에 저장하는 방식으로 사용된다

연동을 해보고 싶었지만, 연동을 하기위해선 인증된 서버의 url이 필요했고,
연동까지는 구현해보지 못했다

프론트에서는 카카오에 등록한 redirect_uri와 사이트 도메인을 이용하여
query_string으로 이루어진 code를 가지고 오고

code를 이용하여 access_token을 발급받아 백엔드로 넘겨주게 된다

이 이후 백엔드에서는 access_token을 이용하여
카카오에서 유저의 정보를 가지고 온다

class KakaoSignIn(View):
    def post(self, request):
        try:
            data             = json.loads(request.body)
            access_token     = data["access_token"]
            profile_json     = requests.get("https://kapi.kakao.com/v2/user/me", headers = {"Authorization":f"Bearer {access_token}"})
            profile          = profile_json.json()
            nickname         = profile.get("kakao_account")["profile"]["nickname"]
            email            = profile.get("kakao_account")['email']
            user, user_exist = User.objects.get_or_create(email = email, name = nickname)
            encoded_jwt      = jwt.encode({"id":user.id}, key = SECRET, algorithm = ALGORITHM)
            return JsonResponse({"Authorization":encoded_jwt}, status = 200)   
        except KeyError:
            return JsonResponse({"message":"KEY_ERROR"}, status = 400)

kakao_login unit test

어떻게 진행해야할지 막막했는데,
초반에는 selenium을 이용해서 유닛테스트를 진행할 수 있지 않을까 생각했다

RequestFactory를 사용해서 request를 만들어 준뒤
url에서 쿼리스트링을 가지고 올 수 있지 않을까해서 시도했고,

selenium을 이용해서 카카오 로그인 화면까지 이동해서 로그인은 성공했지만
그 뒤에 넘어간 url에서 code를 가져올 방법을 생각하지 못해서 다른 방법으로 대체했다

검색해본 결과 외부 api 테스트를 진행 할 때는
python에서 제공하는 MagicMock과 patch를 이용하여
가짜 access_token을 이용하여 테스트를 한다는 걸 발견했고

어떻게 작동하는 걸까 찾아봤다

    @patch("users.views.requests")
    def test_kakao_sign_in_success(self, request):
        class FakeKakaoResponse:
            def json(self):
                return {
                    "kakao_account":{
                        "profile":{
                            "nickname":"딸기검"
                        },
                        "email":"sol3535200@naver.com"
                    }
                }

실제 네트워크의 통신을 막기 위해서 patch를 사용

access_token을 이용해서 카카오에서 json정보를 가지고 오기 때문에
가짜 access_token을 사용하여 json.dumps에 넣어주어 request.body를 통해
통신을 진행함

FakeKakaoResponse 클래스의 이름은 바뀌어도 상관 없지만
json메서드를 변경해줄 경우

카카오 로그인 view에서 json을 가지고 오지 못함

request.user = user 를 저장하는 것처럼
request.get에 MagicMock을 이용하여 FakeKakaoResponse를 저장해줌

그렇기 때문에 request.get에 저장된 정보와
profile.get했을때 가지고 오는 정보가 일치한다면 테스트 통과

그렇다면 KakaoSignIn에 존재하는 profile_json = FakeKakaoResponse인가?

프린트해본 결과 access_token을 통해 가지고오게 되는 정보가
FakeKakaoResponse로 대체된걸 확인 할 수 있엇고,

왜 FakeKakaoResponse 클래스를 만들고 그 안의 메서드가 json이 되어야 하는지
확인할 수 있었다.

이 방법을 응용하면 email, sms도 유닛테스트를 진행할 수 있지 않을까 생각한다

profile
딸기검 -본캐🐒 , 김준형 - 현실 본캐 🐒
post-custom-banner

0개의 댓글