훈훈훈

파이썬(Django) :: 인증 데코레이터(Decorator) 클래스 본문

파이썬/Django

파이썬(Django) :: 인증 데코레이터(Decorator) 클래스

훈훈훈 2020. 2. 17. 15:44

#  Why 인증 데코레이터

 HTTP 프로토콜은 각각의 통신이 독립적이기 때문에 이전에 사용자가 인증을 했는지 알 수 없으며, 새로운 페이지로 넘어 갈떄마다 인증을 해줘야는 문제점이 있다.

이를 해결하기 위해 모든 클래스/함수에 인증 기능을 추가할 수는 있지만 코드가 복잡해지고 길어지기 때문에 인증 기능을 구현 후 데코레이터를 사용하는 것이 좋다,

 

# 인증 데코레이터 클래스

import jwt
import json

from account.models   import Account
from mysite.settings  import SECRET_KEY
from django.http      import JsonResponse

class LoginConfirm:
    def __init__(self, original_function):
        self.original_function = original_function

    def __call__(self, request, *args, **kwargs):
        token = request.headers.get("Authorization", None)
        try:
            if token:
                token_payload = jwt.decode(token, SECRET_KEY, algorithms="HS256")
                user          = Account.objects.get(name=token_payload['name'])
                request.user  = user
                return self.original_function(self, request, *args, **kwargs)

            return JsonResponse({'messaege':'NEED_LOGIN'}, status=401)

        except jwt.ExpiredSignatureError:
            return JsonResponse({'message':'EXPIRED_TOKEN'}, status=401)

        except jwt.DecodeError:
            return JsonResponse({'message':'INVALID_USER'}, status=401)

        except Account.DoesNotExist:
            return JsonResponse({'message':'INVALID_USER'}, status=401)

 

*  _ _call_ _

  : 클래스를 함수처럼 호출시킬 수 있는 함수, 데코레이터 함수에서의 wrapper 함수의 역할을 함

 

*  token = request.headers.get("Authorization", None)
  : 전송된 HTTP 요청에서  "authorization" 헤더 값을 읽은 후 access token을 얻음

 

* token_payload = jwt.decode(token, SECRET_KEY, algorithms="HS256")

  : JWT를 암호화할때 사용한 SECRET_KEY와 해쉬 알고리즘을 사용하여 token을 복호화 후 token_payload 변수에 할당

 

*  user = Account.objects.get(name=token_payload['name']) 

   : 복호화한 JWT의 사용자 name을 변수에 할당 후 이후에 비교할 사용자 name과 비교할때 사용

 

# 인증 기능을 사용한 덧글 클래스

import json

from .models import Comment

from django.views import View
from core.utils   import LoginConfirm
from django.http  import HttpResponse, JsonResponse

class CommentView(View):
    @LoginConfirm    
    def post(self, request):
        data = json.loads(request.body)
        Comment.objects.create(name=request.user.name, comment=data['comment']).save()
  
        return HttpResponse(status=200)
    
    def get(self, request):
        comment_data = Comment.objects.values()
        return JsonResponse({'comments': list(comment_data)}, status=200)

- 위에서 만든 인증 데코레이터를 할당하여 comment를 작성할때 인증을 하도록 작성하였다.

 

# 결과

wave@Waveui-MacBookPro http -v localhost:8080/comment/input-comment Authorization:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiMDIxNSJ9.82cpfuCc-_-peNlckW9a1_WVRx-DdXlMVzyHHeVaLGo" comment="input - comment"
POST /comment/input-comment HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiMDIxNSJ9.82cpfuCc-_-peNlckW9a1_WVRx-DdXlMVzyHHeVaLGo
Connection: keep-alive
Content-Length: 30
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.0.0

{
    "comment": "input - comment"
}

HTTP/1.1 200 OK
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Mon, 17 Feb 2020 04:27:12 GMT
Server: WSGIServer/0.2 CPython/3.7.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

- Authorization에 토큰 값을 전달 후 comment 를 작성하면 200 OK 가 출력되는 것을 확인할 수 있다.

 

Comments