[4th TeamProject] - 로그인

장현웅·2023년 10월 23일
0

메인 페이지에서 로그인 한 유저의 프로필 이미지를 띄워주기 위해 Access Token에 프로필 이미지의 URL을 넣어주기 위한 작업을 진행했습니다.

from django.conf import settings
from rest_framework.exceptions import AuthenticationFailed
from rest_framework import serializers
from user.models import User, ProfileImage
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.validators import UniqueValidator
from django.contrib.auth.password_validation import validate_password


class LoginSerializer(TokenObtainPairSerializer):
    """DRF의 JWT 로그인 방식에 사용되는 TokenObtainPairSerializer를 상속하여 Serializer를 커스터마이징하여 재정의합니다."""

    def validate(self, request_data):
        print(request_data)
        request_email = request_data.get('email')
        request_password = request_data.get('password')

        try:
            user = User.objects.get(email=request_email)
        except User.DoesNotExist:
            raise AuthenticationFailed("사용자를 찾을 수 없습니다. 로그인 정보를 확인하세요.")

        if not user.check_password(request_password):
            raise AuthenticationFailed("비밀번호가 일치하지 않습니다.")
        elif user.is_active == False:
            raise AuthenticationFailed("이메일 인증이 필요합니다.")
        
        token = super().get_token(user)
        refresh = RefreshToken.for_user(user)
        
        user_profile_img = ProfileImage.objects.get(owner=user)
        token['profile_img'] = str(user_profile_img.profile_img)
        
        return {
            'access': str(token.access_token),
            'refresh': str(refresh)
        }

DRF의 토큰 객체는 JSON직렬화가 가능한 Python 기본 데이터 유형이 아닙니다. 그래서 DRF에서 JWT 토큰 로그인 방식을 사용할 경우 TokenObtainPairSerializer에 정의된 validate 메서드에서 토큰 객체를 직렬화가 가능하도록 문자열 처리(str()를 해줍니다.

class TokenObtainPairSerializer(TokenObtainSerializer):
    token_class = RefreshToken

    def validate(self, attrs: Dict[str, Any]) -> Dict[str, str]:
        data = super().validate(attrs)

        refresh = self.get_token(self.user)

        data["refresh"] = str(refresh)
        data["access"] = str(refresh.access_token)

        if api_settings.UPDATE_LAST_LOGIN:
            update_last_login(None, self.user)

        return data

재정의한 LoginSerializer에서는 이 validate메서드를 오버라이드 하고 있기 때문에 직접 토큰 객체들을 직렬화 가능한 데이터로 변환해줘야 합니다.

return {
    'access': token.access_token,
    'refresh': refresh
}

이렇게 그냥 반환하려고 한다면 TypeError: Object of type AccessToken is not JSON serializable 에러가 발생합니다.

0개의 댓글