[Django] requests 대.제.전. @Signin_Decorator

LILO Ghim·2021년 11월 25일
2

sign-in-decorator

westargram mission(modeling, sign-up, sign-in, authentication, authorization)중 일단락을 짓는 sign-in decoratior 생성하기

해당 서비스를 사용하는 사용자가 회원가입을 거쳐 한 번 로그인을 하게되고, http의 stateless의 성질 때문에 정보가 기록되지 않는데, 해당 사용자에게 서버는 jwt token을 발급하여 한 번 방문했던 사용자로부터 특정 request가 발생할 때, 다시 로그인 하지 않아도 되도록 서버가 정보를 기억하고, 이때 view가 사용하는 것이 jwt sign-in decorator이다.

예를 들어, 회원가입 된 사용자가 게시물을 등록한다고 가정하였을 때, view는 다음과 같다.

class PostView(View):
    @sign_in_decorator
    def post(self, request):                    
        try:
            user     = request.user
            data     = json.loads(request.body)
            describe = data["describe"]
            image    = data["image"]

            validation_url(image)

            Post.objects.create(
                user_id         = user.id,
                image           = image,
                describe        = describe    
            )

            return JsonResponse({'MESSAGE':'CREATED'}, status = 201)

        except ValidationError as e:
            return JsonResponse({"MESSAGE":e.message}, status = 400)
        
        except KeyError:
            return JsonResponse({"MESSAGE":"KEY_ERROR"}, status = 400)
            
 -------------------------------------------------------------------------------------

#decorator

 def sign_in_decorator(func):
    def access_token(self, request, *args, **kwargs):
        try:
            access_token = request.headers.get("Authorization", None)     		# 1
            payload 	 = jwt.decode(access_token, SECRET_KEY, algorithms = ALGORITHM) # 2
            user         = User.objects.get(id = payload['id']) 			# 3
            request.user = user								# 4
            return func(self, request, *args, **kwargs)
            
        except jwt.exceptions.DecodeError:                                                
            return JsonResponse({'MESSAGE':'INVALID_TOKEN'}, status = 400)

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

위 code상에서 decorator를 보면,

  • #1 : 먼저 frontend에서 보낸 http request내 headers의 "Authorization"key의 value인 token을 access_token이라는 변수에 할당

  • #2 : 위 변수에 저장된 token을 decoding해서 payload라는 변수에 할당

    print(payload)
    {'id': 72}
  • #3 : payload라는 변수에 저장된 dictionary 형태의 고객정보에서 'id'값(72)으로 User table에서 해당 user를 객체 형태로 불러와서 user라는 변수에 저장

    print(user)
    User object (72)
  • #4 : #3에서 저장한 객체를 request.user라는 변수에 할당하는데, 이 때 token을 decoding하여 얻은 고객 정보(payload)를 request에 담아 view 함수를 호출할 때 보내어 변수로 사용한다.

    func(self, request, *args, **kwargs)
    

    그.런.데.???????????????

    이 때, "request"라는 변수 또는 인자가 중복되어 반복적으로 사용 되고 있다.
    1) 이 request들은 client가 api server로 보낸 request와 모두 동일한 request인지
    2) request.user는 client가 보낸 request와 관련이 있는 변수인지 단지, request하고, 우리 service에 가입된 회원임이 인증된 회원이라는 것을 직관적으로 전달하고자 만든 변수인지
    3) 각 request는 또 실제로 어떠한 데이터 타입으로 변수를 보내는지 혼동이 되어 각각 print를 해보았다.

  1. views.py에서 인자로 받은 requestrequest.body

    print(request)
    
    <WSGIRequest: POST '/posting/posting'>
    
    print(request.body) #client가 body에 담아 요청한 내용
    
    b'{"image": "https://gaussian37.github.io/assets/img/python/django/django.png", "describe": "django"}'
    
  1. decorator가 매개변수로 받은 request

    print(request)
    
    <WSGIRequest: POST '/posting/posting'>
  1. payload에 담긴 고객 정보를 변수에 할당(user)하고 다시 변수에 할당한 request.user
   print(request.user)
   User object (72)

결과적으로 decorator에서 user의 정보를 request.user에 한 번 더 할당하여 func(self, request, *args, **kwargs)에 담아 보내는데 view에서는 이렇게 전달받은 request에서
1) request.body로 body에 담긴 client의 실제 request를 꺼내서 실행하고,
2) request.user로 실제로 request한 user의 id를 꺼내어 명령을 실행한다.


HOW?

request.user=user 로 변수에 할당하는 순간, python의 문법으로 request['user'] = User object (72)가 되고(python의 dictionary를 만들어주는 문법) request dictionary에 'user': <User: User object (72)> 의 형태로 새로운 dictionary가 생성되어 view 함수로 전달된다.

print(request.__dict__)
{'request' : {asdfwefsdjkfhweiufhjksldfjoiwejf...} .... 'headers' :{........}, 'user' : <User: User object (72)>}

#How?:
request['user'] = User object (72)   #request.user = user
{'user' : User object (72)}

결과

또, 그.런.데.???????????????

request.__dict__에 body는 보이지 않는지 도통 알수가 없어서 request.__dir__()을 출력해보면,

body는 request의 dic에서는 숨겨져서 보이지 않지만, dir에서는 확인이 가능한 것을 볼 수 있다!!! (.....왜지..... 알고싶다요.....) dir이 dic의 상위 개념이라고 봤을 때, body는 dic에서는 제외된다는 것은 알겠다. 근데 왜? 더 중요해서? 덜 중요해서? 후...

profile
킴릴로

0개의 댓글