[210727 TIL - (2)] Django

Choi Rim·2021년 7월 27일
0

Django

목록 보기
15/21
post-thumbnail

token 인증하기

  • 사용자가 로그인을 하면 서버는 사용자에게 token을 반환한다.
  • HTTP 는 stateless 성질을 가지고 있기 때문에 글쓰기나, 댓글 쓰기 등 사용자의 식별이 필요할 때 token을 서버에 건내야 한다.
  • token을 건네받으면 발행해준 token이 맞는지 확인하는 과정을 거쳐야한다.

Authorization

Authorization 헤더

  • 인증 토큰을 서버로 보낼 때 사용하는 헤더.
  • 프론트에서 API 요청같은 것을 할 때 토큰이 없으면 거절당하기 때문에 이 때, Authorization을 사용한다.
  • JWT(Json Web Token) 을 사용한 인증에서 주로 사용 한다.
    ex) Headers : {
    Authorization: Bearer xxx.xxx.xxx
    }
def signin_decorator(func):
    def wrapper(self, request, *args, **kwargs):
        try:
            access_token = request.headers.get('Authorization', None)          
            payload = jwt.decode(access_token, SECRET_KEY, algorithms='HS256')  
            user = User.objects.get(id=payload['id'])                 
            request.user = user                                                

        except jwt.exceptions.DecodeError:                                     
            return JsonResponse({'message' : 'INVALID_TOKEN' }, status=400)

        except User.DoesNotExist:                                          
            return JsonResponse({'message' : 'INVALID_USER'}, status=400)
            
         except:
            return JsonResponse({'message':'KEY_ERROR'}, status=400)

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

    return wrapper
  • token 인증을 위한 데코레이터를 만든다.
  • acess_token = request.headers.get('Authorization', None)
    • access_token은 HTTP Request의 헤더인 Authorization의 값을 가져오고, 없으면 None으로 넘긴다.
  • payload = jwt.decode(access_token, SECRET_KEY, algorithms='HS256')
    • Authorization을 통해 가져온 token을 사용자에게 token을 건내 줄 때 넣었던 SECRET_KEY와 algorithm을 통해 decode해준다.
    • 토큰 발행 시와 동일한 사용자라면 동일한 payload가 반환된다.
    • 여기서 algorithm이 아닌 algorithms을 써야 하는데 아마 decode를 할 때는 리스트 형식으로 저장되어 있는 algorithm 중 하나를 선택하는 방식이라서 s를 붙이는 것 같다. 🤔
  • user = User.objects.get(id=payload['id'])
    >>> payload
    {'id': 1}
    >>> payload['id']
    1
    • 위처럼 처음 토큰을 생성할 때 넣었던 payload 정보가 저장되었다.
    • payload 정보는 딕셔너리 형태로 저장되기 때문에 딕셔너리 키로 키값에 접근할 수 있다.
    • 이 키값을 이용해서 user objects에 접근한다.
  • request.user = user
    • HTTP에서 받은 Request에 user변수를 저장해 데코레이터 다음에 나오는 함수에서 사용한다.
    • 토큰 정보를 확인하는 HTTP Request 에는 토큰을 제외하고는 사용자 정보가 들어오지 않기 때문에, 이 user 값을 저장해서 이후 활용한다.

token 인증 시 발생할 수 있는 error 💣

request에 token이 존재할 때

  • token이 유효할 때
    • 에러 발생하지 않음
  • token이 빈 문자열일 때
    • jwt.exceptions.DecoderError: Not enough segments
  • token의 header가 손상되었을 때
    • jwt.exceptions.DecodeError
  • token의 payload가 손상되었을 때
    • jwt.exceptions.DecodeError
  • token의 signature가 손상되었을 때
    • InvalidSignatureError

이 때 DecodeError로만 except 처리해도 InvalidSignatureError가 같이 핸들링 된다. InvalidSignatureError는 DecodeError를 인자로 받는다. 그래서 DecodeError만 처리해도 같이 처리된 것이다.
무슨 오류인지 세부적으로 알려주는 역할이다.

request에 token이 없을 때(key조차 없음) - KeyError

이 때 request.headers['AUTHORIZATION']으로 쓰는지 request.headers.get('AUTHORIZATION')으로 쓰는지는 기획에 달려있다. KeyError를 except 처리해서 다시 로그인 하기를 권하는 쪽으로 빠진다거나, get의 결과로 값이 있는 회원 환경과 None을 받는 비회원 환경에서 다른 뷰를 보여주는 등.


  • except jwt.exceptions.DecodeError: return JsonResponse({'message' : 'INVALID_TOKEN' }, status=400)
    • 없는 토큰 값이 들어왔을 경우 DecodeError를 처리한다.
  • except User.DoesNotExist: return JsonResponse({'message' : 'INVALID_USER'}, status=400)
    • Account 테이블에 매칭되는 값이 없을 경우 DoesNotExist를 처리한다.
    • import 한건 ObjectDoesNotExist 지만 이렇게 쓰면 Attribute Error 가 난다.
      • 객체.DoesNotExist 형태로 쓴다.
  • except: return JsonResponse({'message':'KEY_ERROR'}, status=400)
    • 그 외의 에러 KEY_ERROR로 처리

<참고>

profile
https://rimi0108.github.io/

0개의 댓글