Skip to content

Commit b8b6258

Browse files
authored
fix(jwt): improve JWT secret configuration handling (#307)
1 parent 4a10aa5 commit b8b6258

1 file changed

Lines changed: 66 additions & 47 deletions

File tree

  • base/src/main/java/com/tinyengine/it/login/utils

base/src/main/java/com/tinyengine/it/login/utils/JwtUtil.java

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,25 @@
1717
import io.jsonwebtoken.Claims;
1818
import io.jsonwebtoken.ExpiredJwtException;
1919
import io.jsonwebtoken.Jwts;
20-
import io.jsonwebtoken.MalformedJwtException;
21-
import io.jsonwebtoken.security.Keys;
22-
import jakarta.annotation.PostConstruct;
23-
import lombok.extern.slf4j.Slf4j;
24-
import org.springframework.beans.factory.annotation.Autowired;
25-
import org.springframework.stereotype.Component;
26-
27-
import javax.crypto.SecretKey;
28-
import java.nio.charset.StandardCharsets;
29-
import java.util.ArrayList;
30-
import java.util.Date;
31-
import java.util.HashMap;
32-
import java.util.List;
33-
import java.util.Map;
34-
import java.util.stream.Collectors;
20+
import io.jsonwebtoken.MalformedJwtException;
21+
import io.jsonwebtoken.security.Keys;
22+
import jakarta.annotation.PostConstruct;
23+
import lombok.extern.slf4j.Slf4j;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.core.env.Environment;
26+
import org.springframework.stereotype.Component;
27+
28+
import javax.crypto.SecretKey;
29+
import java.nio.charset.StandardCharsets;
30+
import java.security.SecureRandom;
31+
import java.util.ArrayList;
32+
import java.util.Arrays;
33+
import java.util.Base64;
34+
import java.util.Date;
35+
import java.util.HashMap;
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.stream.Collectors;
3539

3640
/**
3741
* Jwt util
@@ -40,38 +44,53 @@
4044
@Slf4j
4145
public class JwtUtil {
4246

43-
@Autowired
44-
private TokenBlacklistService tokenBlacklistService;
45-
46-
private static final long EXPIRATION_TIME = 21600000L; // 6小时 = 6 * 60 * 60 * 1000 = 21600000 毫秒
47-
private static final String SECRET_ENV_NAME = "SECRET_STRING";
48-
49-
@PostConstruct
50-
public void validateSecretConfiguration() {
51-
try {
52-
getSecretKey();
53-
} catch (Exception e) {
54-
throw new IllegalStateException(
55-
"JWT secret is not configured correctly. Set environment variable "
56-
+ SECRET_ENV_NAME + " to a strong value before starting the service.",
57-
e
58-
);
59-
}
60-
}
61-
62-
private static String getSecretString() {
63-
String secret = System.getenv(SECRET_ENV_NAME);
64-
if (secret == null || secret.isBlank()) {
65-
throw new IllegalStateException(
66-
"Missing required environment variable " + SECRET_ENV_NAME + " for JWT signing."
67-
);
68-
}
69-
return secret;
70-
}
71-
72-
public static SecretKey getSecretKey() {
73-
return Keys.hmacShaKeyFor(getSecretString().getBytes(StandardCharsets.UTF_8));
74-
}
47+
@Autowired
48+
private TokenBlacklistService tokenBlacklistService;
49+
50+
@Autowired
51+
private Environment environment;
52+
53+
private static final long EXPIRATION_TIME = 21600000L; // 6小时 = 6 * 60 * 60 * 1000 = 21600000 毫秒
54+
private static final String SECRET_ENV_NAME = "SECRET_STRING";
55+
private static String cachedSecret;
56+
57+
@PostConstruct
58+
public void validateSecretConfiguration() {
59+
boolean isDev = Arrays.asList(environment.getActiveProfiles()).contains("dev");
60+
String secret = resolveSecret(isDev);
61+
cachedSecret = secret;
62+
if (isDev && System.getenv(SECRET_ENV_NAME) == null) {
63+
log.info("JWT secret auto-generated for dev profile (tokens invalidate on restart)");
64+
}
65+
try {
66+
getSecretKey();
67+
} catch (Exception e) {
68+
throw new IllegalStateException(
69+
"JWT secret is not configured correctly. Set environment variable "
70+
+ SECRET_ENV_NAME + " to a strong value before starting the service.",
71+
e
72+
);
73+
}
74+
}
75+
76+
private static String resolveSecret(boolean isDev) {
77+
String secret = System.getenv(SECRET_ENV_NAME);
78+
if (secret != null && !secret.isBlank()) {
79+
return secret;
80+
}
81+
if (isDev) {
82+
byte[] bytes = new byte[32];
83+
new SecureRandom().nextBytes(bytes);
84+
return Base64.getEncoder().encodeToString(bytes);
85+
}
86+
throw new IllegalStateException(
87+
"Missing required environment variable " + SECRET_ENV_NAME + " for JWT signing."
88+
);
89+
}
90+
91+
public static SecretKey getSecretKey() {
92+
return Keys.hmacShaKeyFor(cachedSecret.getBytes(StandardCharsets.UTF_8));
93+
}
7594

7695
/**
7796
* 生成包含完整用户信息的 JWT Token(支持 Tenant 对象和 Map 两种格式)

0 commit comments

Comments
 (0)