안녕하세요. 지난 포스트에서는 Python에서 Authentication&Authorization(인증&인가) 하는 내용을 기재했습니다. 사실 Django 보다는 Python 내용에 가까웠지만 이 포스트가 중요하고 연계성이 있기 때문에 Django로 카테고리를 분류 했습니다.
웹 사이트를 이용할 때, 여러 기능이 있는데 우리는 이 기능을 매번 로그인 하지 않고 사용합니다. 이것은 지난 포스트에서도 말씀 드린 것 처럼 Front-end에서 Local Storage 또는 Session Storage를 이용해 Header에 access token을 달고 request를 보내기 때문입니다.
그리고 이 반복적인 인가 확인을 위해 Decorator를 구현해 인가가 필요한 API function 마다 적용합니다.
1. Authorization Decorator function 만들기
먼저 코드부터 확인해보겠습니다.
1 import jwt
2 import json
3 import requests
4
5 from django.http import JsonResponse
6 from django.core.exceptions import ObjectDoesNotExist
7
8 from my_settings import SECRET_KEY
9 from users.models import User
10
11 def authorization_decorator(func):
12 def wrapper(self, request, *args, **kwargs):
13 try:
14 access_token = request.headers.get('Authorization', None)
15 payload = jwt.decode(access_token,SECRET_KEY['secret'],algorithm='HS256')
16 login_user = User.objects.get(id=payload['id'])
17 request.user = login_user
18
19 except jwt.exceptions.DecodeError:
20 return JsonResponse({'message':'INVALID_TOKEN'},status=400)
21
22 except User.DoesNotExist:
23 return JsonResponse({'message':'INVALID_USER'},status=400)
24
25 return func(self, request, *args, **kwargs)
26
27 return wrapper
Line 1-3: 관련한 python module을 import 해줍니다.
Line 5-6: django에서 필요한 module을 import 해줍니다. 해당하는 ueser가 없을 때를 위해 예외처리 관련한 ObjectDoesNotExist module도 있음을 기억해주세요.
Line 8-9: Secret Key가 저장되어 있는 별도의 파일 my_settings.py와 회원정보의 Model로 데이터를 컨트롤 해야 하므로 User App의 models.py 파일을 import 합니다.
Line 11-12: 일반적으로 사용하는 Decorator와 비슷한 형태로 선언합니다. wrapper의 형태는 만드는 API function과 비슷하게 정의 해줍니다. 저 같은 경우는 API function에 self(객체 자신)과 request를 받게 해놓았습니다. 활용도가 있으므로 *args와 **kwargs도 Arguments로 받아줍니다.
Line 14: request에 있는 Header에 Authorization key를 주어 token value를 받아 옵니다. 만약 header에 값이 없다면 None이 return될 것입니다.
Line 15: jwt의 decode method로 복호화를 진행합니다. 제가 import한 secret_key가 필수입니다. 이 때, access_token의 값이 Null이거나 decode가 되지 않는다면 error가 발생하고 19번 라인으로 예외처리가 됩니다.
Line 16: {"id":15}와 같은 형태인 payload를 가지고 User 객체를 받아옵니다. 저는 이를 login_user라 지칭하였습니다. 만약 DB에 해당하는 user가 없는 경우 22번 라인으로 예외처리가 됩니다.
Line 17: request라는 클래스에 user라는 변수를 지정해 특정 객체를 저장합니다. 이 객체가 실질적으로 API function에 쓰일 값 입니다.
2. Authorization Decorator 활용하기
조금 전 만든 인가 데코레이터 정확히는 API Decorator를 사용하는 API에 붙여 보겠습니다. 예시 코드로 확인해보겠습니다.
저는 Following이라는 User 객체가 다른 User를 Follow 하는 API에 적용 해보았습니다.
1 import json
2
3 from django.http import JsonResponse
4 from django.views import View
5
6 from users.models import User,Following
7 from my_settings import SECRET_KEY
8 from utils import authorization_decorator
9
10 class FollowUserView(View):
11
12 @authorization_decorator
13 def post(self,request):
14 data = json.loads(request.body)
15 user_id = request.user.id
16
17 try:
18 if User.objects.filter(id=data['followed_user_id']).exists():
19 following_users = list(Following.objects.filter(followed_user=data['followed_user_id']).values('following_user_id'))
20
21 for following_user in following_users:
22 if user_id == following_user['following_user_id']:
23 return JsonResponse({'message':'Already Followed'}, status=401)
24
25 Following(
26 followed_user_id = data['followed_user_id'],
27 following_user_id = user_id
28 ).save()
29 return JsonResponse({'message':'SUCCESS'}, status=200)
30
31 return JsonResponse({'message':'INVALID_USER'}, status=401)
32
33 except KeyError:
34 return JsonResponse({'message': 'KEY_ERROR'}, status=400)
우선 관련한 모듈을 import 해줍니다. posts라는 App의 views.py에는 직접적으로 jwt를 사용하지 않기 때문에 import 하지 않았습니다. 가장 중요한 것은 8번 Line에 제가 작성한 authorization_decorator 함수를 import 하는 것이겠네요.
제가 구현한 API에는 Following을 하는 유저(following_user) 즉, 로그인 해서 행위를 하는 user는 'access token'을 통해 받아 오기로 하였습니다. 저에게만 국한되는 것이 아니라 로그인 한 유저가 특정 user를 Following 하는 것이 당연한 과정입니다.
그리고 Following을 당하는 유저(followed_user) 즉, 로그인한 유저에 의해 팔로우 요청을 받은 유저는 request의 Body를 통해 받아오기로 하였습니다.
Line 12: impact가 빠져 있는데 Decorator로 FollowUserView라는 클래스의 post 함수를 꾸며줍니다.
Line 15: decorator를 통해 받아온 request에 user id를 받아옵니다. 저는 user_id라는 변수로 id만 받았습니다.
Line 18: 먼저 팔로잉 요청을 받는 유저가 존재하는지 확인해줍니다.
Line 19: 조금 복잡해 보일 수도 있는 로직인데 follow 요청을 받는 유저의 기존 following 된 List 자료형으로 받아옵니다. 중복 following이 말이 되지 않기에 이미 follow 하고 있다는 것을 알려주기 위함입니다. DB의 무결성을 위한 것이기도 하죠.
Line 21 - 23: 이미 following 된 경우를 for문으로 찾습니다. header에 있는 user가 있는지 확인하고 있다면 response를 보내줍니다. 이미 Follow 하고 있다는 메세지와 함께요.
Lime 25 - 29: 기존에 Following을 하고 있지 않다면, Following이라는 model 객체에 저장해줍니다.
여기 까지가 decorator를 통해 Following View를 구현한 내용입니다. 실제 view에서는 15번 라인 한 줄로만 사용되어 굉장히 간결하게 느껴집니다.
중요한 것은 Decorator를 구현함으로써 구현할 많은 App에서 인가를 하나하나 구현하지 않아도 된다는 것 입니다.
저는 더 좋은 포스트로 돌아오겠습니다!
'Dev > Django' 카테고리의 다른 글
WebSite(wiselyshave) Clone Project - Part1.시작&데이터모델링 (1) | 2020.07.27 |
---|---|
Django - QuerySet 활용하기(select_related & prefetch_related) (2) | 2020.07.26 |
Django 응용하기 Authentication & Authorization(인증&인가 - Bcrypt와 JWT) (3) | 2020.07.19 |
Django 이해하기 Part3. 많이 사용하는 파일(views.py) (0) | 2020.07.12 |
Django 이해하기 Part2. 많이 사용하는 파일(urls.py, models.py) (0) | 2020.07.12 |