Django 로그인 Decorator

최창환·2022년 3월 27일
0
post-thumbnail

Decorator

Decorator는 사전에 하고싶은 작업을 전처리하는 함수로서 본 함수가 실행되기 전에 미리 생성된 함수를 실행하므로 코드 재활용에 엄청난 도움이 된다.
만약 Decorator함수를 사용하지 않으면 우리는 권한이 필요한 각 View에 Token이 유효한지 확인하는 코드를 계속 작성해야 한다.

Login Decorator

users app에 utils.py라는 새로운 파일을 만들어 Token을 decode하는 과정의 코드를 넣고 각 View에 Decorator 함수를 추가한다.

# users/utils.py

import json, jwt

from django.conf  import settings
from django.http  import JsonResponse

from users.models import User

def SignInDecorator(func):
    def wrapper(self, request, *args, **kwargs):
        try:
            # get 메소드로 HTTP Request의 Header로부터 JWT를 받는다.
            # Authorization 키를 통해 토큰을 받아야 되는데 키가 없으면 NONE type 자료형을 담는다
            access_token = request.headers.get('Authorization', None)          
            # JWT를 발급할때 사용한 SECRET_KEY와 ALGORITHM으로 Token을 Decode한다.
            payload      = jwt.decode(access_token, settings.SECRET_KEY, settings.ALGORITHM)  
            # Decode한 JWT로부터 User ID를 알아내어 권한을 부여받은 User를 저장한다.
            user   	     = User.objects.get(id=payload['id'])                 
            request.user = user

            return func(self, request, *args, **kwargs)
                                                
	# Token이 적합하지 않은 경우 INVALID_TOKEN 에러를 반환한다.
    # (None type을 decode할 때 나오는 에러를 잡기 위해)
        except jwt.exceptions.DecodeError:                                        
            return JsonResponse({'message' : 'INVALID_TOKEN'}, status=401)
	# User가 존재하지 않은 경우 INVALIDE_USER 에러를 반환한다.
        except User.DoesNotExist:
            return JsonResponse({'message' : 'INVALID_USER'}, status=401)

    return wrapper

토큰 정보를 확인하는 HTTP Request에는 토큰을 제외하고는 사용자 정보가 들어오지 않기 때문에 user값을 request.user에 저장해서 이후 활용한다.

PostingView & Decorator

앞서 구현한 Decorator 함수를 PostingView에 적용시켜 보았다.

class PostingView(View):
    @SignInDecorator
    def post(self, request):
        try:
            data      = json.loads(request.body)
            image_url = data['image_url']
            content   = data['content']
            user      = request.user

            if not User.objects.filter(email=data['email']).exists():
                return JsonResponse({'message':'INVALID_USER'}, status=401)

            Posting.objects.create(
                image_url = image_url,
                content   = content,
                user      = user.id
            )

            return JsonResponse({'message':'SUCCESS'}, status=201)

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

    @SignInDecorator
    def get(self, request, posting_id):
        if not Posting.objects.filter(id=posting_id).exists():
            return JsonResponse({'message':'NON_POST'}, status=400)

        posting  = Posting.objects.get(id=posting_id)
        # postings = Posting.objects.all()
        results  = []
        results.append(
            {
                'user'       : posting.user.email,
                'image_url'  : posting.image_url,
                'content'    : posting.content,
                'created_at' : posting.created_at
            }
        )

        return JsonResponse({'results':results}, status=200)

로그인을 하여 서버에서 주는 access_token을 활용하여 PostingView의 GET메소드를 실행시켜 확인해보았다.

Client가 request에 access_token을 첨부하여 보내면 Server는 이 access_token을 복호화하여 User의 id를 얻고, 이 id의 권한을 확인하여 충분한 권한을 가지고 있으면 요청을 처리하고, 그렇지 않다면 Error를 반환한다.

Token이 틀렸을 경우

Token이 일치한 경우

profile
포기하지 않는 개발자

0개의 댓글

관련 채용 정보