Authentication 절차가 끝나면 사용자는 access_token
을 발급받는다.
POST /user/sign-in HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 53
Content-Type: application/json
Host: localhost:8000
User-Agent: HTTPie/0.9.8
{
"email": "test05@test.net",
"password": "123123123"
}
HTTP/1.1 200 OK
Content-Length: 119
Content-Type: application/json
Date: Thu, 16 Apr 2020 12:58:56 GMT
Server: WSGIServer/0.2 CPython/3.8.2
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo2fQ.OhgYyfgDfZIYKt5k9GmE9VpIYKRqqAy6X_hCC_8BIU4"
}
발급받은 토큰은 유저가 요청하는 request에 대한 권한을 검증할때 쓰인다.
ex) 회원이 댓글을 작성할때 정상적으로 로그인이 되어 있는지에 대한 여부, 댓글 작성의 권한이 있는지에 대한 여부
하지만 유저의 권한을 검증할때 매번 이와 같은 절차를 반복하는 코드를 작성할수는 없다. 코드의 가독성이 떨어지고 개발자의 실수가 충분히 일어날수 있다. decorator를 작성하면 decorator 함수가 무조건 먼저 실행되기 때문에. 자주 사용하는 권한 검증에 대한 로직을 decorator로 구현하면 편하게 가져다가 사용할 수 있다.
decorator는 자주 사용되므로 django app에 utils.py를 따로 작성하여 관리하는게 좋다
def login_required(func):
secret = SECRET_KEY
def wrapper(self, request, *args, **kwargs):
try:
payload = jwt.decode(request.headers['Authorization'], secret, algorithm = 'HS256')
user_id = payload['user_id']
request.user = User.objects.get(id = user_id)
return func(self, request, *args, **kwargs)
except jwt.DecodeError:
return JsonResponse({'Message' : 'INVALID_TOKEN'}, status = 400)
except User.DoesNotExit:
return JsonResponse({'Message' : 'INVALID_USER'}, status = 400)
return wrapper
하나하나 살펴보자
payload = jwt.decode(request.headers['Authorization'], secret, algorithm = 'HS256')
request에 header에서 가져온 access_token을 decoding한다. 정상적으로 decode되면 사용자의 id 정보가 담긴 payload({'user_id' : 1})
가 담긴다. decoding이 실패할 경우를 대비해 jwt.DecodeError
예외처리를 해준다.
user_id = payload['user_id']
payload는 dictionary 형식이므로 bracket notation을 통해 사용자의 id를 가져온다.
request.user = User.objects.get(id = user_id)
기존 DB와 대조해 사용자가 존재하는지 확인한다. 사용자가 존재하지 않을 경우를 대비해 User.DoesNotExist
예외처리를 해준다. 정상적으로 사용자가 존재할 경우, request 객체에 user 변수를 만들어 인가가 완료된 사용자의 객체를 담아준다. request.user 변수는 나중에 decorator 이후 실행된 함수에서 유용하게 사용된다.