token을 사용할 때, Refresh token과 access token으로 나누어 보통 사용합니다.
access token의 만료 시간이 임박했을 때만 refresh해주고 싶은 마음이 있어서, 찾아봤습니다. 같은 상황이신 분들께도 도움이 되었으면 좋겠습니다 : )
✅jwt token 명세 : https://datatracker.ietf.org/doc/html/rfc7519
✅json이 궁금하다면? : https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON
✅decoding 방법: https://prafullkumar77.medium.com/flutter-how-to-decode-jwt-token-using-dart-a9657aeaeedf
(이분이 작성하신 글에 제 설명을 조금 더 덧붙였습니다!)
json web token의 약자입니다. 간략하게 특징을 살펴보자면
token 인증 방식은 대개 이런 식으로 이루어집니다.
jwt는 해당 구조를 가지고 있습니다.
Header - 해당 토큰이 '어떤 알고리즘을 이용해' 서명되었는지(암호화되었는지) 식별합니다.
Payload - 전달하고자 하는 내용을 담고 있습니다. 표준 필드도 있지만, 사용자가 정의해 사용할 수 있습니다.
Signature - base64 URL-safe encoding 방식 + 해싱을 적용한 header 와 payload를 비밀키로 서명한(암호화한) 것입니다.
각 header, payload, signature은 '.'으로 구분되어 나타납니다.
jwt의 예시입니다.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9. // <- header와 payload의 구분.
eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY1MDQ5NzIwLC
JpYXQiOjE2NjUwNDI1MjAsImp0aSI6ImI3NWI5OGJhMWMzZDQ5ZWZh
OGQ4ZThhODUyZGFkYjY2IiwidXNlcl9pZCI6MX0. // payload와 signature의 구분.
PlRA_eHDgtfEYAIP0vDRdCwjx2mqn4imCSFGTW-2FfU
우리는 header, signature의 정보가 필요한 것이 아니라, 보통 payload의 데이터를 보고자 합니다.
먼저, token이 정상적인지 간단하게 검사합니다.
final data = token.split('.');
if (data.length != 3) {
Throw Exception('invalid token');
}
그 후, base64 URL-safe encoding 된 문자열을 decode 합니다.
import 'dart:convert';
String decodeBase64(String str) {
String output = str.replaceAll('-', '+').replaceAll('_', '/');
// 하단 설명 참고.
switch (output.length % 4) {
case 0:
break;
case 2:
output += '==';
break;
case 3:
output += '=';
break;
default:
throw Exception('Illegal base64url string!"');
}
return utf8.decode(base64Url.decode(output));
}
base64 encoding 방법은 2진수의 데이터를 문자 코드에 영향을 받지 않게 공통 ascii 영역의 문자들로 바꾸는 인코딩 방식입니다. 64개의 ascii code를 사용하는데 a-z, A-Z, 0-9, '+', '/' 를 사용하고 있습니다.
다만, '+', '/' 특수 문자는 전송하면 정상적으로 해당 값이 전송되지 않습니다. 그래서 '+'와 '/'를 '-'와 '_'로 바꾸어 준 것이 URL-safe 입니다.
==와 =는 패딩입니다. 0과 같은 역할을 하고 있습니다.
base64는 이런 식으로 encoding 합니다. 그러면 character가 하나라면, 혹은 두 개라면?? 나머지 공간은 무언가로 채워주어야 하는데 이 때 사용되는 것이 '=', '=='입니다.
그래서 '='와 '=='를 결과에 덧붙여 주는 것입니다.
이렇게 만들어낸 String은 'dart:convert' 라이브러리를 이용해 decode하면 됩니다.
import 'dart:convert';
String _decodeBase64(String str) {
String output = str.replaceAll('-', '+').replaceAll('_', '/');
switch (output.length % 4) {
case 0:
break;
case 2:
output += '==';
break;
case 3:
output += '=';
break;
default:
throw Exception('Illegal base64url string!"');
}
return utf8.decode(base64Url.decode(output));
}
Map<String, dynamic> parseJwtPayLoad(String token) {
final parts = token.split('.');
if (parts.length != 3) {
throw Exception('invalid token');
}
final payload = _decodeBase64(parts[1]);
final payloadMap = json.decode(payload);
if (payloadMap is! Map<String, dynamic>) {
throw Exception('invalid payload');
}
return payloadMap;
}
유익한 정보 감사합니다 퍼가요~