React에서는 JWT로 로그인 기능을 구현한다는 것은 익히 들어 알고 있었지만, 왜 JWT를 이용하여 로그인을 해야하는 지는 감이 안잡혔습니다.
Spring + React 스택을 사용하면서 기존에 사용하던 Spring Security의 FormLogin 기능을 구조적으로 이용할 수 없기 때문에 JWT를 사용해야 된다는 것을 깨닫게 되었습니다.
JWT는 Json Web Token의 약자로 JSON 객체로 정보를 안전하게 전송하는 방법을 정의하는 공개된 표준(RFC 7519)입니다.
JWT는 HMAC 알고리즘으로 비밀키를 사용하여 서명될 수 있고, RSA나 ECDSA를 사용한 공개/비공개 키 쌍으로도 서명될 수 있습니다.
JWT 토큰에는 Header, Payload, Signature로 세가지 구성요소로 나뉘어 있으며, 아래와 같은 형태를 지닙니다.
HHHHH.PPPPP.SSSSS
토큰의 첫번째 부분인 헤더(Header)에는 서명시 사용하는 서명 암호화 알고리즘(alg), 사용할 타입(typ) 등 메타 정보가 담겨있습니다.
보통 헤더는 두 부분으로 구성됩니다.
{
"alg": "HS256",
"typ": "JWT"
}
그리고 이 내용들은 JWT를 구성하기 위해 Base64Url로 인코딩됩니다.
토큰의 두번째 부분인 페이로드(Payload)에는 토큰에 담을 정보가 들어있으며, 담는 정보의 한 조각을 클레임(claim)이라고 부릅니다.
클레임에는 크게 세가지 분류로 나뉘어 있습니다.
먼저 등록된 클레임은 서비스에서 필요한 정보들이 아닌 토큰에 대한 정보를 담기 위해 이름이 이미 정해진 클레임들입니다.
iss
: 토큰 발급자 (issuer)sub
: 토큰 제목(subject)aud
: 토큰 대상자(audience)exp
: 토큰 만료시간(expiraton), 형식은 NumericDate로 되어 있어야합니다. (예: 1480849147370)nbf
: Not Before를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.iat
: 토큰이 발급된 시간(issued at), 이 값을 사용하여 토큰의 age가 얼마나 되었는지 판단할 수 있습니다.jti
: JWT의 고유 식별자로서, 주로 중복적인 처리 방지를 위해 사용됩니다.각 클레임들은 선택적(optional)으로 포함할 수 있습니다.
공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용됩니다. 충돌을 방지하기 위해서는, 클레임 이름을 URI 형식으로 짓습니다.
{
"https://localhost/jwt_claims/is_admin": true
}
비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장합니다.
{
"username": "admin"
}
{
"username": "admin",
"auth": "ROLE_USER,ROLE_ADMIN",
"https://localhost/jwt_claims/is_admin": true
"exp": 1724135496,
"iat": 1724133696
}
토큰의 마지막 부분인 서명(Signature)은 토큰을 인코딩하거나 유효성을 검증할 때 사용하는 고유한 암호화 코드입니다.
서명(Signature)을 만들기 위해서는 위에서 만든 헤더(Header)와 페이로드(Payload)의 값을 각각 BASE64로 인코딩하고, 인코딩한 값을 비밀 키를 이용해 헤더(Header)에서 정의한 알고리즘으로 해싱하고, 이 값을 다시 BASE64로 인코딩하여 생성합니다.
Spring과 React는 각각 Server, Client로 볼 수 있습니다.
로그인 프로세스는 다음과 같습니다.
Spring에서는 다음과 같은 항목을 구현해야 합니다.
React에서는 다음과 같은 항목을 고려해야 합니다.
이번 포스팅에서는 다음과 같은 항목에 의해 포스팅하였습니다.😊
다음 포스팅에서는 Spring에서 구현해야될 항목에 대해 포스팅하겠습니다~🙌