diff --git a/devkit-core/src/main/resources/logback.xml b/devkit-core/src/main/resources/logback.xml
index af1c7a3..f229a7e 100644
--- a/devkit-core/src/main/resources/logback.xml
+++ b/devkit-core/src/main/resources/logback.xml
@@ -17,22 +17,16 @@
-->
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file
diff --git a/devkit-utils/src/main/resources/logback.xml b/devkit-utils/src/main/resources/logback.xml
index af1c7a3..f229a7e 100644
--- a/devkit-utils/src/main/resources/logback.xml
+++ b/devkit-utils/src/main/resources/logback.xml
@@ -17,22 +17,16 @@
-->
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 5a6c492..7873702 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -21,7 +21,7 @@ slf4jVersion=2.0.9
lombokVersion=1.18.30
jacksonVersion=2.16.0
javaJwtVersion=4.4.0
-jjwtVersion=0.11.5
+jjwtVersion=0.12.5
okhttpVersion=4.12.0
springVersion=6.1.1
springBootVersion=3.2.0
diff --git a/guid/src/main/resources/logback.xml b/guid/src/main/resources/logback.xml
index af1c7a3..5ba9d1b 100644
--- a/guid/src/main/resources/logback.xml
+++ b/guid/src/main/resources/logback.xml
@@ -15,24 +15,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file
diff --git a/property-guard-spring-boot-starter/src/main/resources/logback.xml b/property-guard-spring-boot-starter/src/main/resources/logback.xml
new file mode 100644
index 0000000..f229a7e
--- /dev/null
+++ b/property-guard-spring-boot-starter/src/main/resources/logback.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+ ${COLOURFUL_OUTPUT}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/simple-jwt-authzero/src/main/resources/logback.xml b/simple-jwt-authzero/src/main/resources/logback.xml
index af1c7a3..f229a7e 100644
--- a/simple-jwt-authzero/src/main/resources/logback.xml
+++ b/simple-jwt-authzero/src/main/resources/logback.xml
@@ -17,22 +17,16 @@
-->
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file
diff --git a/simple-jwt-facade/src/main/resources/logback.xml b/simple-jwt-facade/src/main/resources/logback.xml
index af1c7a3..f229a7e 100644
--- a/simple-jwt-facade/src/main/resources/logback.xml
+++ b/simple-jwt-facade/src/main/resources/logback.xml
@@ -17,22 +17,16 @@
-->
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file
diff --git a/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/JjwtTokenResolver.java b/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/JjwtTokenResolver.java
index ba1f12f..7e63aec 100644
--- a/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/JjwtTokenResolver.java
+++ b/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/JjwtTokenResolver.java
@@ -28,17 +28,16 @@ import cn.org.codecrafters.simplejwt.constants.PredefinedKeys;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
import cn.org.codecrafters.simplejwt.exceptions.WeakSecretException;
import cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig;
-import com.fasterxml.jackson.core.type.TypeReference;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SecureDigestAlgorithm;
import lombok.extern.slf4j.Slf4j;
+import javax.crypto.SecretKey;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
-import java.security.Key;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -46,7 +45,7 @@ import java.util.*;
/**
* The {@link JjwtTokenResolver} class is an implementation of the {@link
- * cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code
+ * TokenResolver} interface. It uses the {@code
* io.jsonwebtoken:jjwt} library to handle JSON Web Token (JWT) resolution.
* This resolver provides functionality to create, extract, verify, and renew
* JWT tokens using various algorithms and custom payload data.
@@ -92,7 +91,7 @@ import java.util.*;
* @see Claims
* @see Jws
* @see Jwts
- * @see SignatureAlgorithm
+ * @see SecureDigestAlgorithm
* @see Keys
* @since 1.0.0
*/
@@ -101,14 +100,21 @@ public class JjwtTokenResolver implements TokenResolver> {
private final GuidCreator> jtiCreator;
- private final SignatureAlgorithm algorithm;
+ private final SecureDigestAlgorithm algorithm;
private final String issuer;
- private final Key key;
+ private final SecretKey key;
private final JjwtTokenResolverConfig config = JjwtTokenResolverConfig.getInstance();
+ /**
+ * Create a resolver with specified algorithm, issuer, secret and guid strategy.
+ *
+ * @param algorithm specified algorithm
+ * @param issuer specified issuer
+ * @param secret specified secret
+ */
public JjwtTokenResolver(GuidCreator> jtiCreator, TokenAlgorithm algorithm, String issuer, String secret) {
if (Objects.isNull(secret) || secret.isBlank()) {
throw new IllegalArgumentException("A secret is required to build a JSON Web Token.");
@@ -129,6 +135,13 @@ public class JjwtTokenResolver implements TokenResolver> {
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}
+ /**
+ * Create a resolver with specified algorithm, issuer, secret and default guid strategy.
+ *
+ * @param algorithm specified algorithm
+ * @param issuer specified issuer
+ * @param secret specified secret
+ */
public JjwtTokenResolver(TokenAlgorithm algorithm, String issuer, String secret) {
if (secret == null || secret.isBlank()) {
throw new IllegalArgumentException("A secret is required to build a JSON Web Token.");
@@ -149,6 +162,13 @@ public class JjwtTokenResolver implements TokenResolver> {
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}
+ /**
+ * Create a resolver with specified issuer, secret, default algorithm and guid strategy.
+ *
+ * @param issuer specified issuer
+ * @param secret specified secret
+ * @see #JjwtTokenResolver(TokenAlgorithm, String, String)
+ */
public JjwtTokenResolver(String issuer, String secret) {
if (secret == null || secret.isBlank()) {
throw new IllegalArgumentException("A secret is required to build a JSON Web Token.");
@@ -169,6 +189,12 @@ public class JjwtTokenResolver implements TokenResolver> {
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}
+ /**
+ * Create a resolver with specified issuer, random secret string, default algorithm and guid strategy.
+ *
+ * @param issuer specified issuer
+ * @see #JjwtTokenResolver(String, String)
+ */
public JjwtTokenResolver(String issuer) {
this.jtiCreator = UUID::randomUUID;
this.algorithm = config.getAlgorithm(TokenAlgorithm.HS256);
@@ -176,26 +202,6 @@ public class JjwtTokenResolver implements TokenResolver> {
this.key = Keys.hmacShaKeyFor(SecretCreator.createSecret(32, true, true, true).getBytes(StandardCharsets.UTF_8));
}
- private String buildToken(Duration expireAfter, String audience, String subject, Map claims) {
- var now = LocalDateTime.now();
- var builder = Jwts.builder()
- .setHeaderParam("typ", "JWT")
- .setIssuedAt(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
- .setNotBefore(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
- .setExpiration(Date.from(now.plus(expireAfter).atZone(ZoneId.systemDefault()).toInstant()))
- .setSubject(subject)
- .setAudience(audience)
- .setIssuer(this.issuer)
- .setId(jtiCreator.nextId().toString());
-
- if (claims != null && !claims.isEmpty()) {
- builder.addClaims(claims);
- }
-
- return builder.signWith(key, algorithm)
- .compact();
- }
-
/**
* Creates a new token with the specified expiration time, subject, and
* audience.
@@ -280,10 +286,10 @@ public class JjwtTokenResolver implements TokenResolver> {
*/
@Override
public Jws resolve(String token) {
- return Jwts.parserBuilder()
- .setSigningKey(key)
+ return Jwts.parser()
+ .verifyWith(key)
.build()
- .parseClaimsJws(token);
+ .parseSignedClaims(token);
}
/**
@@ -300,7 +306,7 @@ public class JjwtTokenResolver implements TokenResolver> {
public T extract(String token, Class targetType) {
var resolvedToken = resolve(token);
- var claims = resolvedToken.getBody();
+ var claims = resolvedToken.getPayload();
try {
var bean = targetType.getConstructor().newInstance();
@@ -351,9 +357,9 @@ public class JjwtTokenResolver implements TokenResolver> {
@Override
public String renew(String oldToken, Duration expireAfter) {
var resolvedToken = resolve(oldToken);
- var tokenPayloads = resolvedToken.getBody();
+ var tokenPayloads = resolvedToken.getPayload();
- var audience = tokenPayloads.getAudience();
+ var audience = tokenPayloads.getAudience().toArray(new String[]{})[0];
var subject = tokenPayloads.getSubject();
PredefinedKeys.KEYS.forEach(tokenPayloads::remove);
@@ -372,8 +378,8 @@ public class JjwtTokenResolver implements TokenResolver> {
*/
@Override
public String renew(String oldToken, Duration expireAfter, Map payload) {
- var resolvedTokenClaims = resolve(oldToken).getBody();
- var audience = resolvedTokenClaims.getAudience();
+ var resolvedTokenClaims = resolve(oldToken).getPayload();
+ var audience = resolvedTokenClaims.getAudience().toArray(new String[]{})[0];
var subject = resolvedTokenClaims.getSubject();
return createToken(expireAfter, audience, subject, payload);
@@ -404,8 +410,8 @@ public class JjwtTokenResolver implements TokenResolver> {
*/
@Override
public String renew(String oldToken, Duration expireAfter, T payload) {
- var resolvedTokenClaims = resolve(oldToken).getBody();
- var audience = resolvedTokenClaims.getAudience();
+ var resolvedTokenClaims = resolve(oldToken).getPayload();
+ var audience = resolvedTokenClaims.getAudience().toArray(new String[]{})[0];
var subject = resolvedTokenClaims.getSubject();
return createToken(expireAfter, audience, subject, payload);
@@ -424,4 +430,26 @@ public class JjwtTokenResolver implements TokenResolver> {
public String renew(String oldToken, T payload) {
return renew(oldToken, Duration.ofMinutes(30), payload);
}
+
+ private String buildToken(Duration expireAfter, String audience, String subject, Map claims) {
+ var now = LocalDateTime.now();
+ var builder = Jwts.builder()
+ .header().add("typ", "JWT")
+ .and()
+ .issuedAt(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
+ .notBefore(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
+ .expiration(Date.from(now.plus(expireAfter).atZone(ZoneId.systemDefault()).toInstant()))
+ .subject(subject)
+ .issuer(this.issuer)
+ .audience().add(audience)
+ .and()
+ .id(jtiCreator.nextId().toString());
+
+ if (claims != null && !claims.isEmpty()) {
+ builder.claims(claims);
+ }
+
+ return builder.signWith(key, algorithm)
+ .compact();
+ }
}
diff --git a/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/config/JjwtTokenResolverConfig.java b/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/config/JjwtTokenResolverConfig.java
index 89eefba..677682d 100644
--- a/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/config/JjwtTokenResolverConfig.java
+++ b/simple-jwt-jjwt/src/main/java/cn/org/codecrafters/simplejwt/jjwt/config/JjwtTokenResolverConfig.java
@@ -22,8 +22,12 @@ import cn.org.codecrafters.simplejwt.config.TokenResolverConfig;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException;
import cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver;
+import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.MacAlgorithm;
+import io.jsonwebtoken.security.SecureDigestAlgorithm;
+import javax.crypto.SecretKey;
import java.util.HashMap;
import java.util.Map;
@@ -57,15 +61,15 @@ import java.util.Map;
* @version 1.1.1
* @since 1.0.0
*/
-public final class JjwtTokenResolverConfig implements TokenResolverConfig {
+public final class JjwtTokenResolverConfig implements TokenResolverConfig> {
private JjwtTokenResolverConfig() {
}
- private static final Map SUPPORTED_ALGORITHMS = new HashMap<>() {{
- put(TokenAlgorithm.HS256, SignatureAlgorithm.HS256);
- put(TokenAlgorithm.HS384, SignatureAlgorithm.HS384);
- put(TokenAlgorithm.HS512, SignatureAlgorithm.HS512);
+ private static final Map> SUPPORTED_ALGORITHMS = new HashMap<>() {{
+ put(TokenAlgorithm.HS256, Jwts.SIG.HS256);
+ put(TokenAlgorithm.HS384, Jwts.SIG.HS384);
+ put(TokenAlgorithm.HS512, Jwts.SIG.HS512);
}};
private static JjwtTokenResolverConfig instance;
@@ -95,7 +99,7 @@ public final class JjwtTokenResolverConfig implements TokenResolverConfig getAlgorithm(TokenAlgorithm algorithm) {
if (!SUPPORTED_ALGORITHMS.containsKey(algorithm)) {
throw new UnsupportedAlgorithmException("""
The request algorithm is not supported by our system yet. Please change to supported ones.""");
diff --git a/simple-jwt-jjwt/src/main/resources/logback.xml b/simple-jwt-jjwt/src/main/resources/logback.xml
new file mode 100644
index 0000000..f229a7e
--- /dev/null
+++ b/simple-jwt-jjwt/src/main/resources/logback.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+ ${COLOURFUL_OUTPUT}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/simple-jwt-spring-boot-starter/src/main/resources/logback.xml b/simple-jwt-spring-boot-starter/src/main/resources/logback.xml
index af1c7a3..f229a7e 100644
--- a/simple-jwt-spring-boot-starter/src/main/resources/logback.xml
+++ b/simple-jwt-spring-boot-starter/src/main/resources/logback.xml
@@ -17,22 +17,16 @@
-->
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file
diff --git a/webcal/src/main/resources/logback.xml b/webcal/src/main/resources/logback.xml
index af1c7a3..5ba9d1b 100644
--- a/webcal/src/main/resources/logback.xml
+++ b/webcal/src/main/resources/logback.xml
@@ -15,24 +15,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
+
-
-
- %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n
+
+ ${COLOURFUL_OUTPUT}
-
-
-
- %date{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{50}) : %msg%n
-
-
-
-
+
\ No newline at end of file