1. JWS 생성
String jws = Jwts.builder() // (1)
.setSubject("Joe") // (2)
.signWith(key) // (3)
.compact() // (4)
(1) JwtBuilder 객체를 생성하고 Jwts.builder() 메서드를 이용한다.
(2) header 파라미터와 claims를 추가하기 위해 JwtBuilder 메서드를 호출한다.
(3) JWT를 서명하기 위해 SecretKey나 PrivateKey를 지정한다.
(4) 마지막으로 압축하고 서명하기 위해 compact()를 호출하고, jws를 생성한다.
✅Header
Header parameters
JWT Header는 JWT의 claims와 관련된 컨텐처, 형식, 암호화 작업에 대한 메타 데이터를 제공한다.
JWT 파라미터는 하나 이상 JwtBuilder setHeaderParam 메서드로 한 번 혹은 여러 번 설정할 수 있다.
String jws = Jwts.builder()
.setHeaderParam("kid", "myKeyId")
.....
setHeaderParam을 호출하면 key-value 쌍으로 header에 추가하고, 기존에 key가 존재하면 값을 덮어쓴다.
※ alg, zip 헤더는 자동으로 설정하므로 설정할 필요가 없다.
Header Instance
한 번에 header를 지정하기를 원하면 Jwts.header() 메서드를 사용한다.
Header header = Jwts.header();
populate(header);
String jws = Jwts.builder()
.setHeader(header)
............
※ setHeader를 호출하면 header에 이미 있는 key의 value를 덮어쓴다. alg 및 zip도 마찬가지이다.
✅ Claims
Claims는 JWT의 body이고 JWT 생성자가 JWT를 받는 이들에게 제시하기 바라는 정보를 포함한다.
Standard Claims
JwtBuilder는 JWT 스펙에 정의한 기본으로 등록된 claim names에 대해서 다음과 같은 편리한 setter 메서드를 제공한다.
- setIssuer : iss (Issuer) Claim
- setSubject : sub (Subject) Claim
- setAudience : aud (Audience) Claim
- setExpiration : exp (Expiration Time) Claim
- setNotBefore : nbf (Not Before) Claim
- setIssuedAt : iat (Issued At) Claim
- setId : jit (JWT Id) Claim
다음과 같이 설정한다.
String jws = Jwts.builder()
.setIssuer("me")
.setSubject("Bob")
.setAudience("you")
.setExpiration(expriation) // a java.util.Date
.setNotBefore(notBefore) // a java.util.Date
.setIssuedAt(new Date()) // for example, now
.setId(UUID.randomUUID()) // just an example id
................
Custom Claims
기본적으로 등록된 클레임에 없는, 사용자가 지정하는 클레임을 설정하고 싶을 때 JwtBuilder claim 메서드를 사용한다.
String jws = Jwts.builder()
.claim("hello", "world")
...............
claim이 호출되면 Claims 인스턴스에 key-value 쌍의 데이터가 추가되며 기존에 있는 key-value는 덮어쓴다.
Claims Instance
모든 Claim을 한번에 지정하고 싶다면 Jwts.claims() 메서드를 사용하여 claims 인스턴스를 받아서 작업하면 된다.
Claims claims = Jwts.claims();
populate(claims); //implement me
String jws = Jwts.builder()
.setClaims(claims)
....................
※ setClaims를 호출하면 기존에 있는 같은 이름의 claims를 덮어쓴다.
✅ Signing Key
JwtsBuilder의 signWith 메서드를 호출하여 sign key를 지정하고, JJWT가 지정된 key에 허용된 가장 안전한 알고리즘을 결정하도록 하는게 좋다.
String jwt = Jwts.builder()
.........
.signWith(key) // <--
.compact();
signWith를 사용할 때 JJWT는 연관된 알고리즘 식별자와 함께 alg header도 자동으로 설정한다.
※ 참고 : publicKey를 이용한 JWT 서명은 항상 불안정하기 때문에 사용할 수 없다. JJWT는 어떤 publicKey를 이용한 서명도 InvalidKeyException을 던지고 거부한다.
Secret Formats
HMAC-SHA 알고리즘과 문자열 secret key 또는 인코딩된 byte array를 사용해서 JWT에 서명하는 경우 signWith 메서드 인수로 사용할 secretKey 인스턴스로 변환해야 한다.
인코딩된 byte array
SecretKey key = Keys.hmacShaKeyFor(encodedKeyBytes);
Base64 인코딩된 문자열
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));
Base64URL 인코딩된 문자열
SecretKey key = keys.hmacShakeyFor(Decoders.BASE64URL.decode(scretString));
인코딩 안된 문자열
SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
SignatureAlgorithm Override
종종 주어진 key에 대해서 기본 알고리즘을 override 해서 사용하고 싶을 수 있다.
예를 들면 2048bit의 RSA privateKey가 있다면, JJWT는 자동으로 RS256 알고리즘을 선택한다. 하지만 RS384 또는 RS512를 사용하고 싶으면 추가 파라미터로 SignatureAlgorithm을 허용하는 signWith 메서드의 인자로 넘기면 된다.
.sighWith(privateKey, SignatureAlgorithm.RS512) // <--
.compact();
2. Reading a JWS
Jws<Claims> jws;
try{
jws = Jwts.parseBuilder() // (1)
.setSigningKey(key) // (2)
.build() // (3)
.parseClaimsJws(jwsString)// (4)
...............
} catch (JwtException ex) { // (5)
}
다음과 같이 JWS를 읽어온다.
(1) Jwts.parseBuilder메서드를 이용하여 JwtParseBuilder 인스턴스를 생성한다.
(2) JWS 서명 검증을 위한 SecretKey 혹은 비대칭 PublicKey를 지정한다.
(3) 스레드에 안전한 JwtParser를 리턴하기 위해 JwtParserBuilder의 build() 메서드를 호출한다.
(4) 마지막으로 원본 JWS를 생성하는 JWS를 가지고 parseClaimsJws(String) 메서드를 호출한다.
(5) 파싱이나 서명 검증 오류의 경우 try / catch 구문으로 전체를 감싼다.
✅ Verification Key
JWS를 읽을 때 가장 중요한 것은 JWS의 암호화된 서명을 검증하기 위해 사용하는 지정된 키이다. 서명 검증에 실패하면 JWT는 신뢰할 수 없고, 폐기되어야 한다.
JWS가 SecretKey 로 서명되었으면, 같은 secretkey가 JwtParserBuilder에 지정되어야 한다.
Jwts.parserBuilder()
.setSigningKey(secretKey) // <--
.build()
.parseClaimsJws(jwsString);
JWS가 PrivateKey로 서명되어 있으면 그 key에 대응하는 publickey가 JwtParserBuilder에 지정되어야 한다.
Jwts.parserBuilder()
.setSigningKey(publicKey) // <-- publickey, not privatekey
.build()
.parseClaimsJws(jwsString);
'Java' 카테고리의 다른 글
JWS / JWT (0) | 2024.07.02 |
---|---|
BufferedReader, BufferedWriter (0) | 2024.06.17 |
H2 데이터 베이스 (1) | 2024.06.14 |
[Java] StringTokenizer 문자열 분리 (split과 차이) (0) | 2024.06.14 |
[Java] System.arraycopy 사용법 (0) | 2024.03.22 |