User Registration&Authenticate with JWT

김동완·2022년 7월 22일
0

DRF For Biginners

목록 보기
3/8
post-thumbnail

User Registration (Email/Password)

Class Based View

  • 클래스 기반으로 View 함수를 작성하는 것

왜 CBV를 사용하는가?

  • Django의 많은 기능을 상속할 수 있기 때문

GenericAPIView

  • DRF에서는 GenericAPIView에 CreateModelMixin,ListModelMixin 등 다양한 클래스를 결합해 APIView를 구현한다.
  • GenericAPIView는 CRUD에서 공통적으로 사용되는 다양한 속성을 제공하고, Mixin은 CRUD에서 특정 기능을 수행하는 메소드를 제공한다.
  • DRF에서는 GenericAPIView와 Mixin으로 대부분 API View를 구성하지만, 상황과 모델, 요청에 따라 메소드를 Override 해서 커스텀을 진행한다.

Register

class RegisterAPIView(GenericAPIView) :
    
    
    serializer_class=RegisterSerializer 
    
    
    def post(self,request) :
        serializers = self.serializer_class(data=request.data)  
        
        if serializers.is_valid() :
            serializers.save()
            return response.Response(serializers.data,status=status.HTTP_201_CREATED)
        return response.Response(serializers.errors,status=status.HTTP_400_BAD_REQUEST)
  • serializer_class
    • 요청을 받은 값에 대해 직렬화를 진행하며, 유효성 평가를 할 수 있는 클래스를 지정한다.
    • serializer는 보통 개발자의 의도에 따라 Model에 맞추어 등록하고, 요청을 받을 Model을 대상으로 직렬화 class를 만든다.

Serializer

  • 사용자가 우리 프로그램에 json 데이터를 보낼 때 이를 파이썬 네이티브 객체로 바꾸는 역할을 한다.

  • 왜냐하면 사용자가 JSON 데이터를 보낼 때 모델 객체처럼 매핑을 해야하기 때문

  • 이것을 연결하는데 도움을 주는 것이 serializer이다.

  • 또한 이를 python 객체를 json으로 변환하여 유저에게 제공한다.

class RegisterSerializer(serializers.ModelSerializer) :
    
    password = serializers.CharField(max_length=128,min_length=6,write_only=True)
	#password를 write_only로 설정하여, API 결과로는 보이지 않게 할 수 있다 .    
    class Meta() :
        model=User
        fields = ('username','email','password',)
        
    
    def create(create,validated_data) :
        
        return User.objects.create_user(**validated_data)

Authenticate a user. Get JWT Access Token.

Views.py

#토큰으로 인증된 유저 정보 가져오기 
class AuthUserAPIView(GenericAPIView) :
    
    permission_classes=(permissions.IsAuthenticated,)
    def get(self,request) :
        # print(request.user)

        user = request.user
        serializers=RegisterSerializer(user)
        
        return response.Response({'user':serializers.data})
    
class LoginAPIView(GenericAPIView) :
    authentication_classes=[]
    serializer_class = LoginSerializer
    def post(self,request) :
        email = request.data.get('email',None)
        password = request.data.get('password',None)
        
        user = authenticate(username=email,password=password)
        
        if user :
            
            serializer =  self.serializer_class(user)
            
            return response.Response(serializer.data,status=status.HTTP_200_OK)
        return response.Response({'message':"Invaild credentials,try again"},status=status.HTTP_401_UNAUTHORIZED)

JWT

from rest_framework.authentication import get_authorization_header,BaseAuthentication
from rest_framework import exceptions
import jwt
from django.conf import settings

from authentication.models import User

class JWTAuthentications(BaseAuthentication) :
    
    def authenticate(self, request):
        print(request.data)
        #요청에서 header를 가져온다. 
        auth_header = get_authorization_header(request)
        print(auth_header)
        #받은 header를 utf-8로 디코딩한다. 
        auth_data = auth_header.decode('utf-8')
        print(auth_data)
        #token 형식이 Bearer + Token 이므로, ' '로 나눈다. 
        auth_token = auth_data.split(' ')
        print(auth_token)
        
        #토큰이 있는 리스트 길이가 2여야 하는데, 그렇지 않으면 유효하지 않은 토큰 
        if len(auth_token)!=2 :
            raise exceptions.AuthenticationFailed('Token not valid')
        
        #토큰만 취한다. 
        token=auth_token[1]
        
        try:
            #토큰과 SECRET_KEY, 발급시 사용한 알고리즘을 이용해서 디코딩한다. 
            payload=jwt.decode(token,settings.SECRET_KEY,algorithms='HS256')
            print(payload)
            #디코딩 결과로 얻은 username으로 유저 정보를 가져온다. 
            username=payload['username']
            
            
            user=User.objects.get(username=username)
            
            return (user,token)
            
        #만료된 토큰일경우 예외처리 
        except jwt.ExpiredSignatureError as ex:
            raise exceptions.AuthenticationFailed('Token is expired, login again')
        
        #디코딩 에러일 경우 예외처리 
        except jwt.DecodeError as ex:
            raise exceptions.AuthenticationFailed('Token is invalid')
        
        #토큰 정보로 가져온 User가 존재하지 않을 경우 예외처리 
        except User.DoesNotExist as no_user:
            raise exceptions.AuthenticationFailed(
                'No Search user'
            )
        
        
        return super().authenticate(request)

settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'authentication.jwt.JWTAuthentications',
    ]
}

API 요청 결과

profile
내가 공부한 내용들이 누군가에게 도움이 될지 몰라서 쓰는 벨로그

0개의 댓글