JWT
JSon Web Token는 데이터를 안전하고 간결하게 전송하기 위해 고안된 인터넷 표준 인증 방식
토큰 인증 방식에서 가장 범용적으로 사용
Json 포맷의 토큰 정보를 인코딩 후, 인코딩된 토큰 정보를 Secret Key로 서명한 메세지를 Web Token으로써 인증 과정에 사용
액세스 토큰
리프레시 토큰
보호된 정보들에 접근할 수 있는 권한 부여에 사용
실제 권한을 얻는데 사용
짧은 유효 기간
긴 유효 기간
탈취 당하지 않도록 주의가 필요
JWT는 Header, Payload, Signature로 이루어져있다.
토큰의 타입
서명 생성에 사용하는 알고리즘
{
"alg": "HS512",
"typ": "JWT"
}
Claim이라는 사용자나 토큰에 대한 속성을 key-value의 형태로 저장
iss, sub, aud, exp, nbf, iat, jti와 같은 표준 스펙이 있지만 꼭 포함해야 하는 것은 아님
암호화가 걸려있지 않기에 민감한 정보를 담지 않는 것이 중요
{
"sub": "information",
"iat": 151623391,
"exp": 151623391
}
원하는 비밀 키와 Header에서 지정한 알고리즘으로 Header와 Payload에 대해서 단방향 암호화를 수행
암호화된 메세지로 토큰의 위변조 유무를 검증
Signature의 구조
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
) secret base64 encoded
상태를 유지하지 않고(Stateless), 확장에 용이한 (Scalable) 애플리케이션 구현에 용이
토큰이 만료되기 전까지 한 번의 인증만 수행
인증을 담당하는 시스템을 다른 플랫폼으로 분리하기에 용이
쿠키, 세션과는 달리 base64 인코딩을 통한 정보를 전달하므로 전달량이 많고, 네트워크에 부하가 갈 수 있다.
토큰이 탈취당하는 경우 만료될 때까지 대처할 수 없다.
Payload에는 암호화가 되어있지 않아 민감한 정보를 저장할 수 없다.
JWT 생성 및 검증 테스트를 수행하는데 필요한 라이브러리
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
public class JwtTokenizer {
public String encodeBase64SecretKey(String secretKey){
return Encoders.BASE64.encode(secretKey.getBytes(StandardCharsets.UTF_8));
}
public String generateAccessToken(Map<String, Object> claims,
String subject,
Date expiration,
String base64EncodedSecretKey){
Key key = getKeyEncodedBase64(base64EncodedSecretKey);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(Calendar.getInstance().getTime())
.setExpiration(expiration)
.signWith(key)
.compact();
}
public String generateRefreshToken(String subject,
Date expiration,
String base64EncodedSecretKey){
Key key = getKeyEncodedBase64(base64EncodedSecretKey);
return Jwts.builder()
.setSubject(subject)
.setIssuedAt(Calendar.getInstance().getTime())
.setExpiration(expiration)
.signWith(key)
.compact();
}
private Key getKeyEncodedBase64(String base64EncodedSecretKey){
byte[] keyBytes = Decoders.BASE64.decode(base64EncodedSecretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
}
encodeBase64SecretKey()
: Plain Text 형태인 key를 Base64 형식의 문자열로 인코딩
getKeyEncodedBase64()
: JWT의 서명에 사용할 Key를 생성
Decoders.BASE64.decode()
: Base64 형식으로 인코딩된 Secret Key를 디코딩하여 byte array 형태로 반환Keys.hmacShaKeyFor()
: key byte array를 기반으로 적절한 HMAC 알고리즘을 적용한 Key 객체를 생성generateAccessToken()
: JWT의 AccessToken을 생성
setClaims()
: 인증된 사용자와 관련된 정보를 설정
setSubject()
: JWT의 제목을 설정
setIssuedAt()
: JWT의 발행 일자를 설정
setExpiration()
: JWT의 만료일시를 설정
signWith()
: 서명을 위한 Key 객체를 설정
compact()
: JWT를 생성하고 직렬화