2월 23, 2022

[인증&인가] JWT / [장고]DoesNotExist

 JWT는 authorization, 즉 인가를 위한 것입니다.


jwt를 이용한 authorization 과정입니다. 서버에 저장되는 것은 없습니다.


반면 기존의 방식은 서버 메모리에 user 정보를 저장합니다


왜 이렇게 jwt를 쓸까요?

대부분의 경우 사이트는 한개의 DB만을 가지고 있지 않습니다. 은행을 예시로 들면, 뱅킹에 대한 서버와- 은퇴자들의 정보를 모아놓은 서버가 별도로 존재할 수 있습니다.


이 상황에서, 각 서버에 따로 유저의 인가 정보를 저장한다면, 유저는 backend에서 서버를 이동(유저는 본인이 서버를 옮겨가는지도 모를 가능성이 높습니다) 할 때마다 로그인을 다시 해줘야 하는 불편함을 겪습니다. 

따라서 client가 마치 같은 서버 안에 있는 것처럼, 두 서버를 자유자재로 왔다갔다 하면서 접속할 수 있게 해주려면, JWT를 사용해줘야 합니다. JWT를 사용하면서 Bank와 Retirement서버가 같은 SECRET_KEY를 공유한다면, 클라이언트는 자유자재로 jwt를 가지고 서버를 왔다갔다 할 수 있기에 매우 편리할 것입니다.


SECRET_KEY가 갑자기 왜 나올까요..?

이것이 JWT의 구조입니다.

  • 헤더에는 알고리즘과 토큰의 타입에 대한 정보가 들어갑니다. 즉, 어떤 타입의 데이터인지, 해시 알고리즘 정보는 무엇인지의 정보가 들어가는 것입니다.
  • 내용에는 실제 보관할 데이터를 담습니다. 여기에는 JWT의 만료시간을 나타내는 exp와 같은 registered claim, 공개용 정보 전달 목적의 public claim, 클라이언트와 서버간 협의 하에 사용하는 private claim등이 있습니다.(유저의 ID, iat-토큰 만들어진 시간, exp 등)
  • 위의 두 가지 요소는 Base64방식으로 인코딩(암호화 아닙니다) 돼 있기에, 누구나 그 안의 정보를 볼 수 있기에, 개인정보를 담아서는 안됩니다. 그래서 유저의 이름 등의 값이 아닌, 보안이 지켜지는 DB안의 PK값을 담는 것입니다,
  • 시그니처는 토큰이 바뀌지 않았다는 것을 verify하는 역할입니다. 시그니처 덕분에 유저는 데이터를 보기만 할 수 있고, 서버에만이 이를 수정할 수 있게 됩니다.
  • 헤더와 내용(페이로드)를 조합하고, SECRET_KEY를 이용하여 해시 값을 만들어 냅니다. 이것이 바로 시그니처입니다. 따라서 SECRET_KEY는 과제에서처럼 외부에 노출되지 않게, my_settings등에 따로 보관하며 사용시에는 import해서 사용합니다.
  • 이 시그니처의 비교를 통해 서버는 유저를 verify합니다. 시그니처가 바뀌었다면, 토큰에 변화가 있다는 뜻입니다.
  • 이때, 사용하는 알고리즘 값도 깃헙 등에 올라가서는 안되는 비즈니스 로직이기에, my_settings에 따로 보관해주는 것이 맞습니다.
    • 알고리즘 값은 상수이기에 컨벤션 상, 대문자로 상수명을 지어야 합니다.


DoesNotExist exception은 모델이 가지고 있는 attributes입니다. 쿼리셋.get()으로 특정 object를 가져오려는 대상이 없으면 이 exception이 발생합니다.

DoesNotExist는 django.core.exceptions.ObjectDoesNotExist의 하위 클래스입니다.

ObjectDoesNotExist 로 except처리를 한다면, object가 없는 모든 경우의 수에 대하여 except문이 발동하지만, 만약 모델클래스의 하위 속성인 DoesNotExist를 사용한다면, 특정 모델 클래스의 exception 만을 잡아낼 수 있습니다. 

또한, DoesNotExist는 모델의 속성인 만큼, 사용시에 Model.DoesNotExist 이렇게 모델을 명시해줘야 합니다.