Skip to content

Commit d257fbf

Browse files
committed
feat: Upgrade jjwt to 0.12.5
1 parent 1a19439 commit d257fbf

File tree

2 files changed

+75
-43
lines changed

2 files changed

+75
-43
lines changed

simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/JjwtTokenResolver.java

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,24 @@
2828
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
2929
import cn.org.codecrafters.simplejwt.exceptions.WeakSecretException;
3030
import cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig;
31-
import com.fasterxml.jackson.core.type.TypeReference;
3231
import io.jsonwebtoken.Claims;
3332
import io.jsonwebtoken.Jws;
3433
import io.jsonwebtoken.Jwts;
35-
import io.jsonwebtoken.SignatureAlgorithm;
3634
import io.jsonwebtoken.security.Keys;
35+
import io.jsonwebtoken.security.SecureDigestAlgorithm;
3736
import lombok.extern.slf4j.Slf4j;
3837

38+
import javax.crypto.SecretKey;
3939
import java.lang.reflect.InvocationTargetException;
4040
import java.nio.charset.StandardCharsets;
41-
import java.security.Key;
4241
import java.time.Duration;
4342
import java.time.LocalDateTime;
4443
import java.time.ZoneId;
4544
import java.util.*;
4645

4746
/**
4847
* The {@link JjwtTokenResolver} class is an implementation of the {@link
49-
* cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code
48+
* TokenResolver} interface. It uses the {@code
5049
* io.jsonwebtoken:jjwt} library to handle JSON Web Token (JWT) resolution.
5150
* This resolver provides functionality to create, extract, verify, and renew
5251
* JWT tokens using various algorithms and custom payload data.
@@ -92,7 +91,7 @@
9291
* @see Claims
9392
* @see Jws
9493
* @see Jwts
95-
* @see SignatureAlgorithm
94+
* @see SecureDigestAlgorithm
9695
* @see Keys
9796
* @since 1.0.0
9897
*/
@@ -101,14 +100,21 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
101100

102101
private final GuidCreator<?> jtiCreator;
103102

104-
private final SignatureAlgorithm algorithm;
103+
private final SecureDigestAlgorithm<SecretKey, SecretKey> algorithm;
105104

106105
private final String issuer;
107106

108-
private final Key key;
107+
private final SecretKey key;
109108

110109
private final JjwtTokenResolverConfig config = JjwtTokenResolverConfig.getInstance();
111110

111+
/**
112+
* Create a resolver with specified algorithm, issuer, secret and guid strategy.
113+
*
114+
* @param algorithm specified algorithm
115+
* @param issuer specified issuer
116+
* @param secret specified secret
117+
*/
112118
public JjwtTokenResolver(GuidCreator<?> jtiCreator, TokenAlgorithm algorithm, String issuer, String secret) {
113119
if (Objects.isNull(secret) || secret.isBlank()) {
114120
throw new IllegalArgumentException("A secret is required to build a JSON Web Token.");
@@ -129,6 +135,13 @@ public JjwtTokenResolver(GuidCreator<?> jtiCreator, TokenAlgorithm algorithm, St
129135
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
130136
}
131137

138+
/**
139+
* Create a resolver with specified algorithm, issuer, secret and default guid strategy.
140+
*
141+
* @param algorithm specified algorithm
142+
* @param issuer specified issuer
143+
* @param secret specified secret
144+
*/
132145
public JjwtTokenResolver(TokenAlgorithm algorithm, String issuer, String secret) {
133146
if (secret == null || secret.isBlank()) {
134147
throw new IllegalArgumentException("A secret is required to build a JSON Web Token.");
@@ -149,6 +162,13 @@ public JjwtTokenResolver(TokenAlgorithm algorithm, String issuer, String secret)
149162
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
150163
}
151164

165+
/**
166+
* Create a resolver with specified issuer, secret, default algorithm and guid strategy.
167+
*
168+
* @param issuer specified issuer
169+
* @param secret specified secret
170+
* @see #JjwtTokenResolver(TokenAlgorithm, String, String)
171+
*/
152172
public JjwtTokenResolver(String issuer, String secret) {
153173
if (secret == null || secret.isBlank()) {
154174
throw new IllegalArgumentException("A secret is required to build a JSON Web Token.");
@@ -169,33 +189,19 @@ public JjwtTokenResolver(String issuer, String secret) {
169189
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
170190
}
171191

192+
/**
193+
* Create a resolver with specified issuer, random secret string, default algorithm and guid strategy.
194+
*
195+
* @param issuer specified issuer
196+
* @see #JjwtTokenResolver(String, String)
197+
*/
172198
public JjwtTokenResolver(String issuer) {
173199
this.jtiCreator = UUID::randomUUID;
174200
this.algorithm = config.getAlgorithm(TokenAlgorithm.HS256);
175201
this.issuer = issuer;
176202
this.key = Keys.hmacShaKeyFor(SecretCreator.createSecret(32, true, true, true).getBytes(StandardCharsets.UTF_8));
177203
}
178204

179-
private String buildToken(Duration expireAfter, String audience, String subject, Map<String, Object> claims) {
180-
var now = LocalDateTime.now();
181-
var builder = Jwts.builder()
182-
.setHeaderParam("typ", "JWT")
183-
.setIssuedAt(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
184-
.setNotBefore(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
185-
.setExpiration(Date.from(now.plus(expireAfter).atZone(ZoneId.systemDefault()).toInstant()))
186-
.setSubject(subject)
187-
.setAudience(audience)
188-
.setIssuer(this.issuer)
189-
.setId(jtiCreator.nextId().toString());
190-
191-
if (claims != null && !claims.isEmpty()) {
192-
builder.addClaims(claims);
193-
}
194-
195-
return builder.signWith(key, algorithm)
196-
.compact();
197-
}
198-
199205
/**
200206
* Creates a new token with the specified expiration time, subject, and
201207
* audience.
@@ -280,10 +286,10 @@ public <T extends TokenPayload> String createToken(Duration expireAfter, String
280286
*/
281287
@Override
282288
public Jws<Claims> resolve(String token) {
283-
return Jwts.parserBuilder()
284-
.setSigningKey(key)
289+
return Jwts.parser()
290+
.verifyWith(key)
285291
.build()
286-
.parseClaimsJws(token);
292+
.parseSignedClaims(token);
287293
}
288294

289295
/**
@@ -300,7 +306,7 @@ public Jws<Claims> resolve(String token) {
300306
public <T extends TokenPayload> T extract(String token, Class<T> targetType) {
301307
var resolvedToken = resolve(token);
302308

303-
var claims = resolvedToken.getBody();
309+
var claims = resolvedToken.getPayload();
304310
try {
305311
var bean = targetType.getConstructor().newInstance();
306312

@@ -351,9 +357,9 @@ public <T extends TokenPayload> T extract(String token, Class<T> targetType) {
351357
@Override
352358
public String renew(String oldToken, Duration expireAfter) {
353359
var resolvedToken = resolve(oldToken);
354-
var tokenPayloads = resolvedToken.getBody();
360+
var tokenPayloads = resolvedToken.getPayload();
355361

356-
var audience = tokenPayloads.getAudience();
362+
var audience = tokenPayloads.getAudience().toArray(new String[]{})[0];
357363
var subject = tokenPayloads.getSubject();
358364

359365
PredefinedKeys.KEYS.forEach(tokenPayloads::remove);
@@ -372,8 +378,8 @@ public String renew(String oldToken, Duration expireAfter) {
372378
*/
373379
@Override
374380
public String renew(String oldToken, Duration expireAfter, Map<String, Object> payload) {
375-
var resolvedTokenClaims = resolve(oldToken).getBody();
376-
var audience = resolvedTokenClaims.getAudience();
381+
var resolvedTokenClaims = resolve(oldToken).getPayload();
382+
var audience = resolvedTokenClaims.getAudience().toArray(new String[]{})[0];
377383
var subject = resolvedTokenClaims.getSubject();
378384

379385
return createToken(expireAfter, audience, subject, payload);
@@ -404,8 +410,8 @@ public String renew(String oldToken, Map<String, Object> payload) {
404410
*/
405411
@Override
406412
public <T extends TokenPayload> String renew(String oldToken, Duration expireAfter, T payload) {
407-
var resolvedTokenClaims = resolve(oldToken).getBody();
408-
var audience = resolvedTokenClaims.getAudience();
413+
var resolvedTokenClaims = resolve(oldToken).getPayload();
414+
var audience = resolvedTokenClaims.getAudience().toArray(new String[]{})[0];
409415
var subject = resolvedTokenClaims.getSubject();
410416

411417
return createToken(expireAfter, audience, subject, payload);
@@ -424,4 +430,26 @@ public <T extends TokenPayload> String renew(String oldToken, Duration expireAft
424430
public <T extends TokenPayload> String renew(String oldToken, T payload) {
425431
return renew(oldToken, Duration.ofMinutes(30), payload);
426432
}
433+
434+
private String buildToken(Duration expireAfter, String audience, String subject, Map<String, Object> claims) {
435+
var now = LocalDateTime.now();
436+
var builder = Jwts.builder()
437+
.header().add("typ", "JWT")
438+
.and()
439+
.issuedAt(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
440+
.notBefore(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
441+
.expiration(Date.from(now.plus(expireAfter).atZone(ZoneId.systemDefault()).toInstant()))
442+
.subject(subject)
443+
.issuer(this.issuer)
444+
.audience().add(audience)
445+
.and()
446+
.id(jtiCreator.nextId().toString());
447+
448+
if (claims != null && !claims.isEmpty()) {
449+
builder.claims(claims);
450+
}
451+
452+
return builder.signWith(key, algorithm)
453+
.compact();
454+
}
427455
}

simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/config/JjwtTokenResolverConfig.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
2323
import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException;
2424
import cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver;
25+
import io.jsonwebtoken.Jwts;
2526
import io.jsonwebtoken.SignatureAlgorithm;
27+
import io.jsonwebtoken.security.MacAlgorithm;
28+
import io.jsonwebtoken.security.SecureDigestAlgorithm;
2629

30+
import javax.crypto.SecretKey;
2731
import java.util.HashMap;
2832
import java.util.Map;
2933

@@ -57,15 +61,15 @@
5761
* @version 1.1.1
5862
* @since 1.0.0
5963
*/
60-
public final class JjwtTokenResolverConfig implements TokenResolverConfig<SignatureAlgorithm> {
64+
public final class JjwtTokenResolverConfig implements TokenResolverConfig<SecureDigestAlgorithm<SecretKey, SecretKey>> {
6165

6266
private JjwtTokenResolverConfig() {
6367
}
6468

65-
private static final Map<TokenAlgorithm, SignatureAlgorithm> SUPPORTED_ALGORITHMS = new HashMap<>() {{
66-
put(TokenAlgorithm.HS256, SignatureAlgorithm.HS256);
67-
put(TokenAlgorithm.HS384, SignatureAlgorithm.HS384);
68-
put(TokenAlgorithm.HS512, SignatureAlgorithm.HS512);
69+
private static final Map<TokenAlgorithm, SecureDigestAlgorithm<SecretKey, SecretKey>> SUPPORTED_ALGORITHMS = new HashMap<>() {{
70+
put(TokenAlgorithm.HS256, Jwts.SIG.HS256);
71+
put(TokenAlgorithm.HS384, Jwts.SIG.HS384);
72+
put(TokenAlgorithm.HS512, Jwts.SIG.HS512);
6973
}};
7074

7175
private static JjwtTokenResolverConfig instance;
@@ -95,7 +99,7 @@ public static JjwtTokenResolverConfig getInstance() {
9599
* TokenAlgorithm}
96100
*/
97101
@Override
98-
public SignatureAlgorithm getAlgorithm(TokenAlgorithm algorithm) {
102+
public SecureDigestAlgorithm<SecretKey, SecretKey> getAlgorithm(TokenAlgorithm algorithm) {
99103
if (!SUPPORTED_ALGORITHMS.containsKey(algorithm)) {
100104
throw new UnsupportedAlgorithmException("""
101105
The request algorithm is not supported by our system yet. Please change to supported ones.""");

0 commit comments

Comments
 (0)