Java中如何通过证书指纹验证跨服务JWT令牌签名?
用S1证书指纹验证JWT签名的Java实现方案
核心思路是:先通过S1的证书指纹确认拿到的是合法的S1证书,再从证书中提取公钥,最后用公钥验证JWT的签名。以下是具体步骤和代码示例:
步骤1:预先存储S1的证书指纹
S2要提前保存好S1公开的证书指纹(通常是SHA-256格式,比如AA:BB:CC:DD...这种带冒号的十六进制形式),用来后续校验证书的合法性。
步骤2:获取S1证书并校验指纹
从可信渠道获取S1的证书文件(比如预先部署在S2本地,或通过安全方式拉取),然后计算该证书的指纹,和存储的S1指纹对比,确认证书未被篡改。
计算证书指纹的代码示例:
import java.io.FileInputStream; import java.security.MessageDigest; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public static String calculateCertFingerprint(String certFilePath) throws Exception { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream(certFilePath)) { X509Certificate cert = (X509Certificate) certFactory.generateCertificate(fis); MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] fingerprintBytes = md.digest(cert.getEncoded()); // 转成标准的带冒号十六进制格式 StringBuilder sb = new StringBuilder(); for (byte b : fingerprintBytes) { sb.append(String.format("%02X:", b)); } return sb.deleteCharAt(sb.length() - 1).toString(); } }
调用该方法后,将返回的指纹与预先存储的S1指纹对比,一致则说明证书是合法的S1证书。
步骤3:从合法证书中提取公钥
确认证书合法后,提取用于验证签名的公钥:
import java.io.FileInputStream; import java.security.PublicKey; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public static PublicKey getPublicKeyFromCert(String certFilePath) throws Exception { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream(certFilePath)) { X509Certificate cert = (X509Certificate) certFactory.generateCertificate(fis); return cert.getPublicKey(); } }
步骤4:用公钥验证JWT签名
这里提供两种常用JWT库的实现:
方式1:使用JJWT库
先添加Maven依赖:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>
验证代码:
import io.jsonwebtoken.Jwts; public static boolean validateJwtSignature(String jwtToken, PublicKey publicKey) { try { Jwts.parserBuilder() .setSigningKey(publicKey) .build() .parseClaimsJws(jwtToken); return true; } catch (Exception e) { // 签名无效、令牌过期、格式错误等异常都会触发返回false return false; } }
方式2:使用Nimbus JOSE + JWT库
添加Maven依赖:
<dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>9.37.3</version> </dependency>
验证代码:
import com.nimbusds.jose.JWSVerifier; import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jwt.SignedJWT; public static boolean validateJwtSignature(String jwtToken, PublicKey publicKey) throws Exception { SignedJWT signedJWT = SignedJWT.parse(jwtToken); JWSVerifier verifier = new RSASSAVerifier((java.security.interfaces.RSAPublicKey) publicKey); return signedJWT.verify(verifier); }
关键注意事项
- 务必确保S1的证书指纹是公开且可信的,避免中间人替换证书
- 验证签名的同时,建议额外校验JWT的过期时间、issuer等声明,确保令牌的完整性和有效性
- 如果S1更新证书,要同步更新S2存储的指纹,避免出现验证失败的情况
内容的提问来源于stack exchange,提问作者meg1311
相关产品推荐
相关产品推荐

