개발기록장

[Web] 인증과 인가(2) -인가란? (+JWT) 본문

TIL/Web

[Web] 인증과 인가(2) -인가란? (+JWT)

yangahh 2021. 2. 7. 18:29

 

** 인증 관련 글

2021/02/07 - [TIL/etc] - [etc] 인증과 인가(1) -인증이란? (+bcrypt)

 

[etc] 인증과 인가(1) -인증이란? (+bcrypt)

인증과 인가는 API에서 가장 자주 구현되는 기능 가운데 하나이다. 자주 구현되는 기능이니 만큼 아주 중요한 개념이니 절대 잊지 말자 1. 인증이란? 인증(Authentication)이란 유저의 identification를 확

devvvyang.tistory.com

 

1. 인가(Authorization)와 인가 절차

인가(Authorization)는 요청을 보낸 유저가 그 서비스를 사용할 수 있는 유저인지를 확인하는 절차이다.

 

인가 = Can you do that? 을 확인하는 과정

 

서버는 그 유저를 어떻게 확인할까? Authorization 절차는 다음과 같다.

  1. 서버에 로그인을 성공한 유저는 인증을 받았다는 표시로 그 서버가 발행한 토큰을 발급받는다.
    보통 이 토큰을 access token 이라고 한다. 이 token에는 user id와 같이 아주 중요한 정보가 아니면서도(예를 들어 주민등록번호 같은) 유저를 확실하게 구분할 수 있는 정보가 있어야 한다.
  2. 인증을 받은 유저는 request를 보낼 때 request header에 보통 'Authorization' 라는 이름으로 token 정보를 담아서 보낸다.
  3. 서버는 이 request에 담긴 token 정보를 복호화하여 우리 서버에서 발급한 token이 맞는지 그리고 token에 담긴 user id를 확인할 수 있다.
  4. token에서 얻은 user id를 사용해서 DB에서 해당 유저의 권한(permission)을 확인한다.
  5. 해당 유저가 그 요청을 사용할 수 있는 권한을 가지고 있으면 해당 요청을 처리한다.
  6. 유저가 권한을 가지고 있지 않은 유저라면 Unauthorized Response(401) 에러 또는 적절한 다른 에러 코드를 보낸다.

 

 

2. JSON Web Token (JWT)

- JWT란?

  1. access token을 생성하는 방법에는 여러가지가 있는데, 그 중 가장 널리 사용되는 기술 중 하나가 바로 JSON Web Token(JWT)이다. 
  2. JSON Web Token (JWT) 은 웹표준 (RFC 7519) 으로서 두 개체에서 JSON 객체를 사용하여 가볍고 자가수용적인 (self-contained) 방식으로 정보를 안전성 있게 전달해주고, 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token이다.
  3. 자가 수용적 이라는 말은 JWT 는 필요한 모든 정보를 자체적으로 지니고 있다는 것을 뜻한다.
  4. 토큰에 대한 기본정보(header), 전달 할 정보(payload), 그리고 토큰이 검증됐다는것을 증명해주는 Signature 를 포함하고있다.
  5. JWT는 양방향 해쉬 알고리즘이 적용되어 있는데, 이를 이용하여 프론트엔드에서는 API요청 시 암호화 된 토큰 정보를 보내고 백엔드에서는 이 토큰을 복호화해서 유저의 권한을 확인한다.

 

- JWT 구조

1) Header

  • Header 는 두가지의 정보를 지니고 있다.
  • typ: 토큰의 타입을 지정. JWT는 JWT이다.
  • alg: Signature 해싱 알고리즘을 지정합니다. 해싱 알고리즘으로는 보통 HMAC-SHA256 혹은 RSA 가 사용되며, 이 알고리즘은 토큰을 검증 할 때 사용되는 signature 부분에서 사용된다.

예시)

{ 
	"alg" : "HS256", 
	"typ" : "JWT" 
}

 

 

2) Payload

  • Paylaod에는 토큰을 통해 전달할 내용이 담겨져있다.
  • 여기에 담긴 하나의 key-value 쌍을 'Claim'이라고 부르고, Registered, Public, Private의 3가지 유형으로 나뉜다.
  • 보통 만료일시, 발급일시, 발급자, 권한정보 등이 포함된 공개 클래임
  • 그리고 클라이언트와 서버간의 협의 하에 사용하는 비공개 클래임이 있다.
  • Header와 Payload 부분은 암호화하지 않고 base64로 인코딩만 하기 때문에 웹에 접속한 호스트라면 누구나 볼 수 있다. 따라서 민감함 정보는 넣지 않고, user id와 값은 PK값을 전달한다.

 

예시)

{ 
	"iss": "http://example.org", 
	"aud": "https://exmple.com", 
	"exp": "1407019629", 
	"http://example.com/jwt_claims/is_admin" : "true", 
	"user_id": "3"
}

 

 

3) Signature

  • signature(서명) 인코딩된 header  payload  합쳐 header signature 알고리즘 정보(alg)를 가져와 암호화하여 생성한다
  • 만약 헤더정보의 알고리즘이 HS256  경우 아래 예시와 같은 signature가 생성된다.
  • 프론트엔드에서 JWT를 백엔드 API 서버로 전송하면 서버에서는 전송받은 JWT의 Signature 부분을 복호화 하여 이 서버에서 생성한 JWT가 맞는지를 확인한다.(내가 만든 건 복호화 가능하기 때문)
  • 마치 계약서의 위변조를 막기 위해 서로 사인하는 것과 같다고 보면된다.

 

HMACSHA256( 
    base64UrlEncode(header) + “.”+ 
    base64UrlEncode(payload), 
    Secret)

 

 

3. JSON Web Token (JWT)으로 인가 구현

 

파이썬에서 JWT를 이용하여 access token을 발급해보자.

 

1) pip로 jwt 패키지 설치

pip install pyjwt

* pyjwt 공식 문서 : pyjwt.readthedocs.io/en/stable/

 

 

2) JWT 토큰 발행 과정

import jwt
import datetime


# JWT 토큰 발행 (만료 시간을 300초로 설정)
encoded_jwt = jwt.encode({'user-id': 5, 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=300)}, 'secret', algorithm='HS256')
  • jwt.encode 함수를 사용하여 토큰을 발행할 수 있다.
  • jwt.encode 함수의 인자는 아래와 같다.
  • ({user_id, 토큰 만료시간 등 payload에 줄 정보}, 'secret key', algorithm='사용할 해싱 알고리즘') 
  • 이때 secret key는 암호화에 이용될 key로 Django project에서는 settings.py에 있는 secret 키를 불러와서 사용한다.

 

 

3) JWT 토큰 검증 (decode)

# 토큰 검증(decode)
payload = jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])

  • jwt.decode 함수를 사용하여 토큰을 검증할 수 있다.
  • jwt.decode 함수의 인자는 아래와 같다. 
  • jwt.decode(검증할 토큰, 'secret key', algorithms=['암호화에 사용된 해싱 알고리즘'])  ** algorithms에 's' 주의!!
  • 이 결과로 payload에 저장된 값을 가져와서 유저의 권한을 확인할 수 있다.