下面是一个使用 nimbus-jose-jwt 库(版本 10.4)验证 JWT Token 的完整实现,基于你提供的 RSA 公钥(JWKS)。
依赖配置
首先确保你的项目中包含以下依赖(Maven配置):
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>10.4</version>
</dependency>
实现代码
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import java.text.ParseException;
import java.util.Base64;
import java.math.BigInteger;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.security.KeyFactory;
import java.util.Date;
public class JwtValidatorNimbus {
// 你的JWT Token
private static final String JWT_TOKEN = "要验证的Token";
// 你的RSA公钥JWK
private static final String JWK_JSON = "JWKS的JSON";
// 预期的Issuer和Audience
private static final String EXPECTED_ISSUER = "Issuer";
private static final String EXPECTED_AUDIENCE = "Audience";
public static void main(String[] args) {
try {
boolean isValid = validateJwt(JWT_TOKEN, JWK_JSON);
System.out.println("Token is valid: " + isValid);
} catch (Exception e) {
System.out.println("Token validation failed: " + e.getMessage());
e.printStackTrace();
}
}
public static boolean validateJwt(String jwtToken, String jwkJson) throws ParseException, JOSEException, java.security.NoSuchAlgorithmException, java.security.spec.InvalidKeySpecException {
// 1. 解析JWT
SignedJWT signedJWT = SignedJWT.parse(jwtToken);
// 2. 从JWK构建RSA公钥
RSAKey rsaKey = RSAKey.parse(jwkJson);
RSAPublicKey publicKey = rsaKey.toRSAPublicKey();
// 3. 验证签名
JWSVerifier verifier = new RSASSAVerifier(publicKey);
if (!signedJWT.verify(verifier)) {
throw new JOSEException("Signature verification failed");
}
// 4. 获取claims
JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
// 5. 验证claims
Date currentTime = new Date();
// 验证过期时间
if (claimsSet.getExpirationTime() == null || claimsSet.getExpirationTime().before(currentTime)) {
throw new JOSEException("Token has expired");
}
// 验证生效时间(如果有)
if (claimsSet.getNotBeforeTime() != null && claimsSet.getNotBeforeTime().after(currentTime)) {
throw new JOSEException("Token is not yet valid");
}
// 验证Issuer
if (!EXPECTED_ISSUER.equals(claimsSet.getIssuer())) {
throw new JOSEException("Invalid issuer");
}
// 验证Audience
if (!claimsSet.getAudience().contains(EXPECTED_AUDIENCE)) {
throw new JOSEException("Invalid audience");
}
// 打印claims信息
System.out.println("Token validated successfully");
System.out.println("Subject: " + claimsSet.getSubject());
System.out.println("Issuer: " + claimsSet.getIssuer());
System.out.println("Expiration: " + claimsSet.getExpirationTime());
System.out.println("Preferred username: " + claimsSet.getStringClaim("preferred_username"));
return true;
}
}
代码说明
1. 解析JWT:
使用 SignedJWT.parse() 方法解析JWT字符串
2. 构建RSA公钥:
- 使用 RSAKey.parse() 方法从JWK JSON字符串构建RSAKey对象
- 然后转换为 RSAPublicKey
3. 验证签名:
-
创建 RSASSAVerifier 验证器
-
使用 signedJWT.verify() 方法验证签名
4. 验证Claims:
-
检查token是否过期
-
检查token是否已生效(如果有nbf声明)
-
验证Issuer是否符合预期
-
验证Audience是否包含预期值
5. 输出验证结果:
-
验证成功返回true
-
验证失败抛出相应异常