API 서비스를 개발하고 이에 대한 접근 권한을 제어하기 위하여 JSON Web Token(JWT)을 활용할 수 있습니다. 이 문서에서는 JWT 토큰의 생성과 유효성 확인 과정을 그림과 Python 코드를 사용하여 설명합니다. 전자서명 알고리즘으로는 HS256을 사용하였습니다.
- HS256(HMAC-SHA256)
- 대칭키 암호화 방식
- HMAC(Hash-based Message Authentication Code)
- 해시 함수를 기반으로 메시지 인증 코드를 생성하는 알고리즘
다음은 토큰 생성과 유효성 확인 과정에서 사용하게 될 Base64 인코딩/디코딩 함수입니다.
import base64
import hashlib
import hmac
def base64_encode(input_as_bytes):
b = base64.urlsafe_b64encode(input_as_bytes).decode('utf-8')
return b.rstrip('=')
def base64_decode(input_as_string):
padding = 4 - len(input_as_string) % 4
input_as_string = input_as_string + '=' * padding
return base64.urlsafe_b64decode(input_as_string.encode('utf-8')).decode('utf-8')
1. 토큰 생성
1.1. 다이어그램
1.2. Python 구현
def create_jwt_token(header_obj_str, payload_obj_str, secret):
header = base64_encode(header_obj_str.encode('utf-8'))
payload = base64_encode(payload_obj_str.encode('utf-8'))
header_plus_payload = f'{header}.{payload}'
m = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
m.update(header_plus_payload.encode('utf-8'))
d = m.digest()
signature = base64_encode(d)
print('** Signature (algorithm: HS256) **')
print(f'Byte size: {len(d)}')
print(f'Base64 encoded: {signature}')
jwt_token = f'{header_plus_payload}.{signature}'
return jwt_token
header_obj_str = '{\
"typ":"JWT",\
"alg":"HS256"\
}'
payload_obj_str = '{\
"iss":"fun-with-jwts",\
"sub":"AzureDiamond",\
"jti":"f6c1097f-cc48-4949-a627-8b94fc5e37ba",\
"iat":1596185001,\
"exp":1596185061\
}'
secret = 'my-secret'
jwt_token = create_jwt_token(header_obj_str, payload_obj_str, secret)
print('** JWT token (structure: header.payload.signature) **')
print(jwt_token)
실행 결과:
** Signature (algorithm: HS256) **
Byte size: 32
Base64 encoded: UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
** JWT token (structure: header.payload.signature) **
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
입력
-
header object
{ "typ": "JWT", "alg": "HS256" }
-
payload object
{ "iss": "fun-with-jwts", "sub": "AzureDiamond", "jti": "f6c1097f-cc48-4949-a627-8b94fc5e37ba", "iat": 1596185001, "exp": 1596185061 }
-
secret
my-secret
출력
-
token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
2. 토큰 유효성 확인
2.1. 다이어그램
2.2. Python 구현
def validate_jwt_token(token, secret):
pos = token.rfind('.')
header_plus_payload = token[:pos]
signature = token[pos+1:]
m = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
m.update(header_plus_payload.encode('utf-8'))
d = m.digest()
signature_derived = base64_encode(d)
return signature_derived == signature
token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k'
secret = 'my-secret'
is_valid = validate_jwt_token(token, secret)
print(f'** is_valid: {is_valid} **')
실행 결과:
** is_valid: True **
입력
-
token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
-
secret
my-secret
출력
-
is_valid
True
Written with StackEdit.