[백업][가리사니] jwt 라이브러리
java, jwt, kotlin
이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.
자바, 코틀린 용 JWT 라이브러리를 만들어봤습니다.
- https://github.com/saro-lab/jwt
QUICK START
gradle kts
implementation('me.saro:jwt:2.0.1')
gradle
compile 'me.saro:jwt:2.0.1'
maven
<dependency>
<groupId>me.saro</groupId>
<artifactId>jwt</artifactId>
<version>2.0.1</version>
</dependency>
자바
단일키 예제
// 사용할 알고리즘 선언
var alg = new JwtEs256();
var key = alg.newRandomJwtKey();
// 클래임스 (payload의 객체) 선언
var claims = JwtClaims.create();
claims.issuedAt(OffsetDateTime.now());
claims.notBefore(OffsetDateTime.now().minusMinutes(1));
claims.expire(OffsetDateTime.now().plusMinutes(30));
claims.id("jti value");
claims.issuer("iss value");
claims.subject("sub value");
claims.audience("aud value");
claims.claim("custom", "custom value");
System.out.println(claims);
// jwt로 만듬 (위 newRandomJwtKey 를 가지고 만듬)
var jwt = alg.toJwt(key, claims);
System.out.println(jwt);
// jwt로부터 새로운 클래임스 생성
var newClaims = Assertions.assertDoesNotThrow(() -> alg.toJwtClaims(jwt, key));
System.out.println(newClaims);
// 비교
Assertions.assertEquals(newClaims.id(), "jti value");
Assertions.assertEquals(newClaims.issuer(), "iss value");
Assertions.assertEquals(newClaims.subject(), "sub value");
Assertions.assertEquals(newClaims.audience(), "aud value");
Assertions.assertEquals(newClaims.claim("custom"), "custom value");
동적키 예제 (header의 kid 사용)
// 사용할 알고리즘 선언
var alg = new JwtEs256();
// 키맵
var keyMap = new HashMap<String, JwtKey>();
// jwt 리스트
var jwtList = new ArrayList<String>();
// 랜덤한 키맵을 만든다.
for (int i = 0 ; i < 30 ; i++) {
var kid = UUID.randomUUID().toString();
var key = alg.newRandomJwtKey();
keyMap.put(kid, key);
// key는 db에 스트링형태로 저장해서 불러와서 파싱할 수 있다.
// 이 원리로 여러서버가 공유 가능하다.
// - key.stringify()
// - alg.toJwtKey(key.stringify())
}
// 랜덤한 키를 가지고 jwt 를 만들어서 jwt 키 리스트에 쌓아둔다.
for (int i = 0 ; i < 10 ; i++) {
var claims = JwtClaims.create();
claims.issuedAt(OffsetDateTime.now());
claims.notBefore(OffsetDateTime.now().minusMinutes(1));
claims.expire(OffsetDateTime.now().plusMinutes(30));
claims.id("jti value " + i);
claims.issuer("iss value " + i);
claims.subject("sub value " + i);
claims.audience("aud value " + i);
claims.claim("custom", "custom value " + i);
var randomKid = (String)keyMap.keySet().toArray()[(int)(Math.random() * keyMap.size())];
var randomKey = keyMap.get(randomKid);
// make jwt with key / kid(header)
var jwt = alg.toJwt(randomKey, claims, randomKid);
jwtList.add(jwt);
}
// 디코드 및 검증
for (int i = 0 ; i < 10 ; i++) {
var jwt = jwtList.get(i);
var header = alg.toJwtHeader(jwt);
var key = keyMap.get(header.getKid());
var claims = alg.toJwtClaims(jwt, key);
System.out.println();
System.out.println("jwt : " + jwt);
System.out.println(header);
System.out.println(claims);
Assertions.assertEquals(claims.id(), "jti value " + i);
Assertions.assertEquals(claims.issuer(), "iss value " + i);
Assertions.assertEquals(claims.subject(), "sub value " + i);
Assertions.assertEquals(claims.audience(), "aud value " + i);
Assertions.assertEquals(claims.claim("custom"), "custom value " + i);
}
코틀린
단일키 예제
// 사용할 알고리즘 선언
val alg = JwtEs256()
val key = alg.newRandomJwtKey()
// 클래임스 (payload의 객체) 선언
val claims = create()
claims.issuedAt(OffsetDateTime.now())
claims.notBefore(OffsetDateTime.now().minusMinutes(1))
claims.expire(OffsetDateTime.now().plusMinutes(30))
claims.id("jti value")
claims.issuer("iss value")
claims.subject("sub value")
claims.audience("aud value")
claims.claim("custom", "custom value")
println(claims)
// jwt로 만듬 (위 newRandomJwtKey 를 가지고 만듬)
val jwt = alg.toJwt(key, claims)
println(jwt)
// jwt로부터 새로운 클래임스 생성
val newClaims = Assertions.assertDoesNotThrow<JwtClaims> { alg.toJwtClaims(jwt, key) }
println(newClaims)
// 비교
Assertions.assertEquals(newClaims.id(), "jti value")
Assertions.assertEquals(newClaims.issuer(), "iss value")
Assertions.assertEquals(newClaims.subject(), "sub value")
Assertions.assertEquals(newClaims.audience(), "aud value")
Assertions.assertEquals(newClaims.claim("custom"), "custom value")
동적키 예제 (header의 kid 사용)
// 사용할 알고리즘 선언
val alg = JwtEs256()
// 키맵
val keyMap = HashMap<String?, JwtKey>()
// jwt 리스트
val jwtList = ArrayList<String>()
// 랜덤한 키맵을 만든다.
for (i in 0..29) {
val kid = UUID.randomUUID().toString()
val key = alg.newRandomJwtKey()
keyMap[kid] = key
// key는 db에 스트링형태로 저장해서 불러와서 파싱할 수 있다.
// 이 원리로 여러서버가 공유 가능하다.
// - key.stringify()
// - alg.toJwtKey(key.stringify())
}
// 랜덤한 키를 가지고 jwt 를 만들어서 jwt 키 리스트에 쌓아둔다.
for (i in 0..9) {
val claims = create()
claims.issuedAt(OffsetDateTime.now())
claims.notBefore(OffsetDateTime.now().minusMinutes(1))
claims.expire(OffsetDateTime.now().plusMinutes(30))
claims.id("jti value $i")
claims.issuer("iss value $i")
claims.subject("sub value $i")
claims.audience("aud value $i")
claims.claim("custom", "custom value $i")
val randomKid = keyMap.keys.toTypedArray()[(Math.random() * keyMap.size).toInt()] as String
val randomKey = keyMap[randomKid]
// make jwt with key / kid(header)
val jwt = alg.toJwt(randomKey!!, claims, randomKid)
jwtList.add(jwt)
}
// 디코드 및 검증
for (i in 0..9) {
val jwt = jwtList[i]
val header = alg.toJwtHeader(jwt)
val key = keyMap[header.kid]
val claims = alg.toJwtClaims(jwt, key)
println()
println("jwt : $jwt")
println(header)
println(claims)
Assertions.assertEquals(claims.id(), "jti value $i")
Assertions.assertEquals(claims.issuer(), "iss value $i")
Assertions.assertEquals(claims.subject(), "sub value $i")
Assertions.assertEquals(claims.audience(), "aud value $i")
Assertions.assertEquals(claims.claim("custom"), "custom value $i")
}