postToken(
- WebClient.RequestBodySpec.FormDataSpec form, String op) {
+ BodyInserters.FormDataSpec form, String op) {
return webClient.post()
.uri(props.getTokenUri())
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
diff --git a/backend/api-gateway/src/main/java/com/deepdata/gateway/infrastructure/casdoor/CasdoorIdTokenVerifier.java b/backend/api-gateway/src/main/java/com/deepdata/gateway/infrastructure/casdoor/CasdoorIdTokenVerifier.java
index 8f2c0bf..1b98f73 100644
--- a/backend/api-gateway/src/main/java/com/deepdata/gateway/infrastructure/casdoor/CasdoorIdTokenVerifier.java
+++ b/backend/api-gateway/src/main/java/com/deepdata/gateway/infrastructure/casdoor/CasdoorIdTokenVerifier.java
@@ -4,7 +4,6 @@ import com.deepdata.gateway.infrastructure.casdoor.dto.JwksResponse;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.security.RSAKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Component;
@@ -13,6 +12,11 @@ import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
@@ -22,7 +26,7 @@ import java.util.Optional;
/**
* Casdoor id_token 验证器:拉取公开 JWKS(带 TTL 缓存),按 {@code kid} 选 RSA 公钥,
- * 用 JJWT(0.11.5,与网关现有 JWT 栈一致)做 RS256 验签 + iss/aud/exp/nbf 校验。
+ * 用 JJWT(0.12.x)做 RS256 验签 + iss/aud/exp/nbf 校验。
*
* 实测(2026-08-30):JWKS 端点 {@code /.well-known/jwks.json} 无需鉴权,返回
*
{"keys":[{"use":"sig","kty":"RSA","kid":"cert-built-in","alg":"RS256","n":"...","e":"AQAB","x5c":["..."]}]}
@@ -40,10 +44,10 @@ public class CasdoorIdTokenVerifier {
private final CasdoorProperties props;
private final WebClient webClient;
- /** JWKS 缓存(kid → RSAKey),证书轮转时靠 TTL / kid 未命中强制刷新 */
+ /** JWKS 缓存(kid → RSAPublicKey),证书轮转时靠 TTL / kid 未命中强制刷新 */
private volatile CacheEntry cache;
- private record CacheEntry(long fetchedAtMillis, Map keys) {}
+ private record CacheEntry(long fetchedAtMillis, Map keys) {}
public CasdoorIdTokenVerifier(CasdoorProperties props) {
this.props = props;
@@ -62,7 +66,7 @@ public class CasdoorIdTokenVerifier {
public Mono verify(String idToken) {
return parseAndVerify(idToken, false)
.flatMap(jws -> {
- Claims body = jws.getBody();
+ Claims body = jws.getPayload();
IdTokenClaims claims = new IdTokenClaims(
body.getSubject(),
body.get("name", String.class),
@@ -123,26 +127,26 @@ public class CasdoorIdTokenVerifier {
});
}
- private Jws parseWithKid(String idToken, Map keys) {
- String kid = Jwts.parserBuilder().build().readHeader(idToken).get("kid", String.class);
- RSAKey key = keys.get(kid);
+ private Jws parseWithKid(String idToken, Map keys) {
+ String kid = Jwts.parser().build().parse(idToken).getHeader().get("kid", String.class);
+ RSAPublicKey key = keys.get(kid);
if (key == null) {
log.warn("casdoor jwks: kid [{}] not cached, size={}", kid, keys.size());
return null;
}
try {
- return Jwts.parserBuilder()
- .setSigningKey(key)
+ return Jwts.parser()
+ .verifyWith(key)
.requireIssuer(props.getIssuer())
.requireAudience(props.getClientId())
.build()
- .parseClaimsJws(idToken);
+ .parseSignedClaims(idToken);
} catch (Exception e) {
throw new CasdoorIdTokenException("id_token verification failed: " + e.getMessage(), e);
}
}
- private Mono