import jwt #토큰 생성, encode/decode
import json #request로 받을 데이터가 json이므로
from .models import Account #로그인시필요한 유저 정보가 담긴 models
from django.http import JsonResponse #토큰및유저 확인후 보낼 response 메세지를 jsonresponse로
def login_required(func):
def wrapper(self, request, *args, **kwargs): [1]
access_token = request.headers.get('Authorization', None) [2]
secret = "wecode" [3]
if access_token: [4]
try:
decode = jwt.decode(access_token, secret, algorithm='HS256') [5]
user = Account.objects.get(id = decode['user']) [6]
request.user = user [7]
except jwt.DecodeError:
return JsonResponse({"message":"잘못된토큰"}, status = 403) [8]
except Account.DoesNotExist:
return JsonResponse({"message":"존재하지않는ID"}, status =401) [9]
return func(self,request, *args, **kwargs) [10]
return JsonResponse({"message": "로그인필요", status = 401} [11]
return wrapper
[1]. func(CommentView
와 같은)가 받을수 있는 인자들을 설정한다. 클라이언트로부터 request를 받을 시 동작하므로, request를 인자로 설정한다. 또한, 쿼리 스트링 값에 따라 여러가지 식별자도 올 수 있으므로, *args
**kwargs
를 설정해 에러가 나지 않도록 한다.
[2]. 클라이언트에게 받은 request정보 안에서도, 토큰 정보는 통상 headers
의 Authorization
key에 저장되어 있다. Authorization
에 value가 없을 경우 (즉 토큰이 없는 경우), None
을 리턴한다. None
을 설정하지 않으면, 없을 경우의 예외처리 코드를 추가해야 하므로, 잊지말자.
headers는 딕셔너리 형식을 가지므로 json.loads
가 필요 없다.
(참고: headers에 커스텀 key를 추가할수있으나, 그런 경우 꼭 settings.py
의 cors headers에서 등록 해주어야 한다.)
[3]. 토큰을 decode할 때 사용할 시크릿키를 변수에 저장한다. 실제로 시크릿 키는 위와 같이 변수에 직접 적어넣지 않고, 외부에 공개하지 않는 파일을 만들어서 그 안에 저장해 두고 필요시 불러와야 한다 데코레이터 함수가 어떻게 작동하는지가 본 글의 목적이므로 이번 경우에는 위와 같이 직접 작성하였다.
[4]. access_token
이 존재하는 경우, 아래 코드를 실행한다.
[5]. 토큰이 일치하는지 확인하기 위하여 bytes => string으로 decode가 필요하다. jwt.decode
를 사용하여 3 parameters를 작성한다.
[6]. [5]에서 저장한 decode한 데이터중, key가 user인 값의 id 를 가져와, user변수에 저장한다. (user는 사용자 ID와 같은 정보)
[7]. user는 request.user
를 통해, request의 user 객체로 저장한다. 이는 데코레이터의 인자로 받을 함수에서 사용할 수 있도록 하기 위해서 이다. 토큰 정보를 확인하는 HTTP Request 에는 토큰을 제외하고는 사용자 정보가 들어오지 않기 때문에, 이 user 값을 저장해서 이후 활용한다.
[8]. 예외처리1: DecodeError
, 토큰 값이 일치 하지 않는 경우 리턴한다.
[9]. 예외처리2: Account.DoesNotExist
, user
가 존재하지 않는 경우 리턴한다.
[10]. 예외에 해당하지 않는 경우, func의 인자들을 리턴한다.
[11]. access_token이 존재하지 않는경우, 로그인이 우선되야 하므로 리턴한다.
클라이언트가 전송한 request http를 Django에서 받는 순간, request는 인스턴스 객체화 되므로, 직접 접근이 가능해 진다. 이 객체는 bytes화 되어 있으며, http의 headers, body뿐만 아니라 다른 요소도 정형화 되어 들어있다.
bytes된 정보도 사실은 여러 부분으로 나누어져 있으며, 앞부분을 해석해 보면 어떤 형식의 데이터 인지를 알 수 있다. 장고가 이 부분을 해독하여, json 데이터 라고 판단하면 json.loads
를 사용하여 json형식으로(key/value)로 바꾸어준다. 이로써, 파이썬은 데이터를 딕셔너리로써 인식/사용할 수 있게 된다.
response의 경우, 딕셔너리 형태의 데이터를 장고가 json format으로 바꾸어 클라이언트에게 돌려준다.
기술적으로는 body에 토큰을 담는것도 가능하다. 하지만, 메소드에(get or post)상관없이 인증정보를 가져와야하므로 header에 담는게 일반적이다.
회원정보를 수정하려면 login에도 get메소드가 필요하다.
참고자료