인가(Authorization)와 JWT

Sua·2021년 2월 8일
0

Web

목록 보기
3/8
post-thumbnail

사진출처

로그인과 서비스 기능 구현 시 알아야 할 인가의 개념과 JWT(JSON Web Token)에 대해서 알아보도록 하자.

인가(Authorization)

인가란?

  • 인가는 유저가 해당 서비스를 사용할 수 있는 권한이 있는지 확인하는 절차이다.
  • 예를 들어, 해당 유저는 고객 정보를 볼 수 있는 있지만 수정 할 수는 없다.
  • 로그인하는 것이랑 어떤 서비스를 사용할 수 있는 것은 별개의 문제이다. 예를 들어 넷플릭스에 로그인을 했어도, 결제를 하지 않은 유저는 영상 재생을 할 수 있는 권한이 없다.
  • 보통 로그인 인증, 인가? 어떻게 구분?
  • (HTTP는 이전 요청과 응답을 기억 못 하는 stateless한 특성을 가지기 때문에, 로그인을 할 때 토큰을 생성한다. 이후 어떤 요청이 있을 때 토큰을 통해 해당 유저 정보을 얻고, 권한을 확인할 수 있다.)

어떤 과정으로 이루어질까?

  1. 인증 절차를 통해 access token을 생성한다. access token에는 user id 등 유저 정보를 확인할 수 있는 정보가 들어가 있어야 한다.
  2. 유저가 request를 보낼때 access token을 첨부해서 보낸다.
  3. 서버에서는 유저가 보낸 access token을 복호화 한다.
  4. 복호화된 데이터를 통해 user id를 얻는다.
  5. user id를 사용해서 DB에서 해당 유저의 권한(permission)을 확인하다.
  6. 유저가 충분한 권한을 가지고 있으면 해당 요청을 처리한다.
  7. 유저가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드를 보낸다.

JSON Web Token(JWT)

  • access token을 생성하는 방법은 여러가지가 있는데, 그 중 가장 널리 사용되는 기술중 하가 바로 JWT(JSON Web Tokens)이다.
  • JWT는 말 그대로 유저 정보를 담은 JSON 데이터를 암호화 해서 클라이언트와 서버간에 주고 받는 것이다.

JWT 구조

헤더(Header)

  • header는 typalg 두 가지 메타정보를 가지고 있다.
    • typ: 토큰의 타입을 지정한다. 바로 JWT 이다.
    • alg: 해싱 알고리즘을 지정한다. 이 알고리즘은 토큰을 검증 할 때 사용되는 signature 부분에서 사용된다.
{"typ":"JWT","alg":"HS256"} 

헤더는 BASE64 방식으로 인코딩해서 JWT의 가장 첫 부분에 기록된다.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

내용(payload)

  • payload 부분에는 토큰에 담을 정보가 들어있다. 여기에 담는 정보의 한 ‘조각’ 을 클레임(claim) 이라고 부르고, 이는 name:value 의 한 쌍으로 이뤄져있다. 토큰에는 여러개의 클레임 들을 넣을 수 있다.
  • 클레임의 종류에는 등록된 (registered) 클레임, 공개 (public) 클레임, 비공개 (private) 클레임이 있다.
  • 내용은 헤더와 마찬가지로 BASE64 방식으로 인코딩해서 기록된다.

등록된(registered) 클레임

  • 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임
  • iss- 토큰 발급자(issuer), exp- 토큰의 만료시간(expiraton) 등이 있고 optional이다.

공개(public) 클레임

  • JWT를 사용하는 사람들에 의해 정의되는 클레임
  • 클레임 충돌을 피하기 위해서 URI 형식으로 정의해야 한다.

비공개(private) 클레임

  • 클라이언트(프론트)와 서버(백)간 협의하에 사용하는 클레임
  • 민감하지 않지만 그 사람의 고유한 정보들이 들어간다.(아이디O, 휴대폰X, 이름X, 주민번호X)
  • payload는 BASE64 인코딩한 것이므로(암호화아님) 누구나 원본을 볼 수 있으니 개인정보를 담아서는 안 되기 때문이다.

서명(signature)

  • 서명은 JWT가 원본 그대로라는 것을 확인할 때 사용하는 부분이다.
  • 서명은 인코드된 header 와 payload 그리고 JWT secret(별도 생성)을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송한다.(복호화 가능)
  • 프론트엔드가 JWT를 백엔드 API 서버로 전송하면 서버에서는 전송받은 JWT의 서명부분을 복호화하여 서버에서 생성한 JWT가 맞는지 확인한다.
  • 마치 계약서의 위변조를 막기위해 서로 사인하는 것과 같다고 보시면 된다.
  • 예를 들어 넷플릭스 토큰으로 마켓컬리를 돌아다니면 안 된다. 따라서 해당 서버에서 만든 토큰은 그 서버에서만 해독이 가능해야 한다. 서명을 복호화해서 우리 서버의 사용자인지 확인한다.

생성된 JWT 예시

PyJWT 사용하기

pyjwt을 설치한다.

pip install pyjwt

pyjwt를 import한다. 패키지명은 pyjwt이지만 임포트할때의 이름은 jwt이다.

import jwt

토큰 발행

access token을 발급한다.

# 시크릿키와 알고리즘 방식은 중요한 정보이므로 my_settings.py등에 따로 저장하고 import해서 사용하는 게 좋다 
SECRET = 'secret_example' 
ALGORITHM = 'HS256'

access_token = jwt.encode({'id' : 1}, SECRET, algorithm = ALGORITHM)

참고로, v2.0.0 이상의 pyjwt이라면 jwt.encode의 반환값이 bytes 타입이 아니라 string 타입이다.

print(access_token)
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI

type(access_token)
<class 'str'>

로그인이 성공하면 위와 같은 방식으로 발행한 토큰을 프론트엔드에게 전달하면 된다.

전달받은 토큰을 프론트 쪽에서 로컬 스토리지, 세션 스토리지, 쿠키 등 어디에 저장할지는 서비스에 따라 다르다.

토큰 검증

인증을 통과한 사용자만 접근하려면 토큰을 받아서 다시 우리가 발행한 토큰이 맞는지 확인 해야한다. decode할 때는 algorithm이 아닌 algorithms으로 입력해야 한다.

header = jwt.decode(access_token, SECRET, algorithms = 'HS256')

decode 결과는 바로 우리가 encode 할 때 넘겼던 payload값인 {'id' : 1}이다.
이 값을 통해 권한이 있는 유저인지 식별할 수 있다.

print(header)
{'id': 1}

pyjwt v2.0.0 버전에 따른 이슈는 이 블로그에 잘 설명되어 있다.

참고사이트
https://velopert.com/2389
https://velopert.com/2350
http://www.opennaru.com/opennaru-blog/jwt-json-web-token/
https://phin09.tistory.com/61

profile
Leave your comfort zone

2개의 댓글

comment-user-thumbnail
2021년 2월 9일

수아님~! 수아님 포스팅 덕분에 로그인 데코레이터 해결했어요~~ 감사합니다 >< 잘 보고 갑니다❤️🍒

1개의 답글