클라이언트에서 받은 토큰을 데코레이터로 이용하는법

Psj·2020년 11월 13일
0

Python

목록 보기
25/41
post-thumbnail

이미지1

이미지2

실행순서

이하는 이미지2의 코드이다.

class BoardEnroll(View):
    @check_user
    def post(self, request):
    

class BoardEnroll(View)내의 함수를 보면
def post 함수위에 @check_user 데코레이터가 붙어있는것을 볼수있다.

이러면 post함수를 실행한다고하면 post함수가 실행되기 바로직전에 먼저 자동으로 데코레이터된 @check_user가 실행되어 이미지1의 함수가 실행된다.

데코레이터가 실행된다면

이미지2의 def post(self, request)가 이미지1의 check_user(func)의 인자인 func로 들어가게 된다.

def check_user(post(self,request)):   # func에 post(self,request)가 들어가게된다.
    def wrapper_func(self, request):
        token=request.headers.get('Authorization',None) #현재 request에는 token에 대한 데이터만 들어있다.
        # Authorization
        if token is None:
            return JsonResponse({'message':'I haven\'t token'},status=400)
        try:
            secret = settings.SECRET_KEY 

            user_id = jwt.decode( token,secret,algorithm='HS256') # 여기서 딕셔너리형식으로 바뀜  
            account = Account.objects.get(id=user_id['id'])
            request.account = account.id 
            # 이 전까지 requset에는 토큰데이터만 들었기 때문에 변수account에 유저에대한 정보를 넣고 그것을 request.account에 넣었다. requset.account는 requset에 user정보를 저장한것이다.
            return post(self,request) # <- 이렇게 post(self,requset)가 들어간다.

        except Account.DoesNotExist:
            return JsonResponse({'message':'unknown_user'},status=401)
        except jwt.DecodeError:
            return JsonResponse({'message':'invalid_token'},status=401)

    return wrapper_func

def check_user(post(self,request)) 가 실행이되면 def check_user(post(self,request))에 들어갈 인자가 선언되어야 하는데 선언되는 값이 없으니
바로 밑으로 내려와 return wrapper_func 이 되어 내부의 def wrapper_func(self, request) 가 실행되게 된다.

내부코드 해석

request 구조

먼저 위에서 함수의 인자로 사용하는 request의 본모습이 class인것을 알아야한다

class request(headers,body,startline)
	def  ...

request는 이렇게 headers,body,startline 이라는 기본속성을 가진 클래스 구조로 이루어져있다.

이미지1 코드 해석

token=request.headers.get('Authorization',None)

현재 블로그에는 나와있지 않지만 아래이미지는 토큰을 보내는 다른파일의 이미지이다.

('Authorization'에 토큰값을 할당하여 클라이언트에 보낸상황이고 )
그 'Authorization'에 할당된 토큰을 그대로 request의 headers의 'Authorization'에 받아온 상황이 현재상황이다.
그리고 해당 코드의 두번째 인자인 None은 토큰을 받아오지못햇을때 None을 실행하라고 만든 것이다.

if token is None:
            return JsonResponse({'message':'I haven\'t token'},status=400)

해당코드는 위에서 말한 None이 실행되었을때 발생되는 메시지를 표현한것이다.


from django.conf import settings

 secret = settings.SECRET_KEY 

import한 settings 내의 있는 SECRET_KEY 키를 이용하기 위해 secret이라는 변수에 담은것이다.

user_id = jwt.decode( token,secret,algorithm='HS256')

jwt.decode를 하면 암호화되어있던 토큰이 딕셔너리 형식으로 변환되게된다.
예) 토큰을 암호화하기전에 담은 딕셔너리형식인 {'id':1} 이렇게 변환된다.

즉 위의 코드인 jwt.decode의 인자들을 해석하면
암호화된 토큰이 담긴 변수명token을 변수명secret에담긴 secret키를 이용하여 algorithm방식인 HS256방식을 이용해서 암호화되기 이전의 형식인 딕셔너리형식으로 변환시킨다는 뜻이되고 그것을 user_id에 담았다는 뜻이된다.

account = Account.objects.get(id=user_id['id'])

models의 class Account의 여러속성들중 get할 속성중 하나를 id로 속성을 정하고
위에서 가져온 user_id에서 ['id']를 정해 로그인한 유저의 토큰의 id벨류값을 정해 이 id벨류값이 존재하는 class Account 의 전체 row(행) 즉, 이 id가 속해 있는 객체를 가져와 account변수명에 담으라는 뜻이다.

request.account = account.id 

이제 account.id는 우리가 원하는 객체(row(행))를 가져온 변수가된다.
여기 id만 빼올것이기때문에 account.id로 id를 특정해준다.

request 구조

먼저 위에서 함수의 인자로 사용하는 request의 본모습이 class인것을 알아야한다

class request(headers,body,startline)
	def  ...

다시 위에서말한 request구조를 보자면 우리는 현재 request의 headers에 담겨온 토큰을 풀어 그에 해당되는 id를 추출해냈다.

우리는 이 추출한 id를 다시 return하기위해 request에 담아야하는데 request에는 이 id를 담을 속성이 없으므로 새로 속성을 만들어줘야한다. 그래서 만든 속성이 속성명account이고 이것을 표현하면 request.account가 되는것이다.

이하는 속성이 추가된 request를 클래스형식으로 표현한것이다

request 속성 추가된 구조

속성인 account를 추가했다.

class request(headers,body,startline,account)
	def  ...

우리는 이 request.account에 account.id를 담은것이다.

return post(self,request)

그리고 모든과정이 정상적으로 실행되었으면 이렇게 post(self,request)로 return이 된다.


이제 이미지1의 데코레이터 과정이 모두 끝나서 토큰의 주인인 유저를 찾을수 있게 되었다!
회원가입이된 유저임이 확인되었으니 이제 다음과정인 정상적인 게시글 등록이 가능하게되었다

이미지2 코드해석

class BoardEnroll(View):
    
    @check_user
    def post(self, request):
        
        data= json.loads(request.body)

        user_token =  Account.objects.get(id = request.account)

        Board.objects.create(enrolled_name = data['name'],
                             contents_title = data['title'],
                             contents = data['contents'],
                             image_url = data['image'],
                             enrolled_time = datetime.now(),
                             user_name = user_token)
        return JsonResponse({'message':'SUCCESS'}, status=200)
data= json.loads(request.body)

클라이언트에서 게시글 입력창에 name, title, contents, image를 입력하면 request.body에 담아 가져오고 그것을 변수명data 담은것이다.

user_token =  Account.objects.get(id = request.account)

데코레이터과정에서 가져온 request.account에 담긴 유저id정보에 맞는 id가 있는 객체(row(행))을 찾아 가져와서 변수명user_token에 담으라는것이다

Board.objects.create(enrolled_name = data['name'],
                             contents_title = data['title'],
                             contents = data['contents'],
                             image_url = data['image'],
                             enrolled_time = datetime.now(),
                             user_name = user_token)

이제 클라이언트에서 입력한 내용을 순서에 맞게 생성하게된다.

이하코드인 맨아랫줄은

user_name = user_token

user_name은 models에서 형식이 ForienKeyField이다.
ForienKeyField는 다른 클래스의 객체(row(행))를 넣으면 그 가져온 객체의 id가 생성되게하는 필드이다.

user_name에 user_token 객체(row(행))을 넣었으니
user_name의 값은 user_token의 id번호가 되고 그 번호를 user_name입장에서는 ForienKey라고 부른다.

profile
Software Developer

0개의 댓글