Java JWT使用公钥字符串验证解析token方法详解
JSON Web Token (JWT) 是一种用于 Web 应用程序处理身份验证的开放标准(RFC 7519),可在不同站点或服务器之间安全地传输声明,泛指声明某个实体(主体)具有某个权限。
本文将介绍如何使用公钥字符串来验证和解析 JWT 令牌,以此保证您的 Web 应用程序的身份验证机制的安全性。
1. 概述
在 JWT 中,以 JSON 对象的形式存储有关该小组成员的所有信息。由于其包含了详细且易于解析的信息,因此该 JWT 的信息对于处理认证非常有用。通常,JWT 由三部分组成,分别是头部、主体和签名。
1.1 头部
头部通常由两部分组成:令牌类型(通常都是 JWT)和所使用的签名算法(例如 HMAC SHA256 或 RSA)。例如:
{
"alg": "RS256",
"typ": "JWT"
}
1.2 主体
主体是 JWT 的有用信息或声明。例如:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
1.3 签名
JWT 的签名通常由三部分组成,即令牌头、令牌主体和密钥的组合加密。签名旨在验证令牌的完整性并明确该令牌是由特定实体签名的。由于签名由密钥生成,因此仅拥有密钥的实体才能创建有效的签名。
2. 使用公钥字符串验证 JWT 令牌
通过使用公钥验证 JWT 令牌可以增加 JWT 令牌的安全性。下面是使用公钥字符串进行 JWT 令牌验证的简单步骤:
- 首先要拥有一个公钥 - 私钥对。
- 获取 JWT 令牌的头部和主体并编码为一个字符串。
- 使用指定的算法生成签名,并将其与 JWT 令牌中的签名进行比较以验证令牌。
- 在验证签名时,必须使用与创建 JWT 令牌时使用的相同的算法,而且必须使用相同的密钥。
2.1 公钥解析
在验证令牌之前,需要通过公钥字符串解析出公钥。可以使用以下代码实现:
String publicKeyString = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1rPDfoW3KlzZfIrpM2o\n" +
"9CS3XvRjz+ViJjHxuCOfY1Hk/rLyMfPc1Jn8zUd4cO/ao6wD+bxHGnG2GxkhY7Dl\n" +
"zddB3SDn/x8gCYy6p8B5PnDXbz1Z4QECEFRdUtpWk0mm3HMqCETv9N/Q65m/KRMQ\n" +
"m5fAjsNYu06JzDQeF7ijSxYDshwUhtfiNdJ1MVSICksWqR91pXe1D4Gmx5zBqLj6\n" +
"aVloR0Srf+b/cDZXyHaaRNrT8yfZixH/kcCYy8T6biDP5gjPqUpatnp9NXp2+WAH\n" +
"tX4DSRpf1mfChnJFYf2jMnLg/W039vp0fyuKVIL7FpoLObWg5q8RlVxgS13qFeE4\n" +
"pwIDAQAB\n" +
"-----END PUBLIC KEY-----";
PublicKey publicKey = null;
try {
publicKey = PemUtils.getPublicKey(publicKeyString);
} catch (PEMException e) {
// handle exception
}
2.2 令牌验证
下面是使用公钥字符串进行 JWT 令牌验证的代码示例:
String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
// 解析JWT令牌,获取头部和主体
String[] tokenPieces = token.split("\\.");
String jwtHeader = tokenPieces[0];
String jwtPayload = tokenPieces[1];
// 拼接签名字符串
String base64UrlHeader = Base64.getUrlEncoder().encodeToString(jwtHeader.getBytes("UTF-8"));
String base64UrlPayload = Base64.getUrlEncoder().encodeToString(jwtPayload.getBytes("UTF-8"));
String signatureInput = base64UrlHeader + "." + base64UrlPayload;
// 验证签名
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
byte[] signatureBytes = Base64.getUrlDecoder().decode(tokenPieces[2].getBytes("UTF-8"));
signature.update(signatureInput.getBytes("UTF-8"));
boolean verified = signature.verify(signatureBytes);
if (!verified) {
throw new InvalidJwtSignatureException("Invalid JWT signature");
}
3. 使用示例
3.1 生成 JWT 令牌
下面是使用 Java 生成 JWT 令牌的示例:
// 创建头部
Map<String, Object> headerClaims = new HashMap<>();
headerClaims.put("alg", "HS256");
headerClaims.put("typ", "JWT");
Header header = new JwtHeader(headerClaims);
// 创建主体
Map<String, Object> bodyClaims = new HashMap<>();
bodyClaims.put("sub", "1234567890");
bodyClaims.put("name", "John Doe");
bodyClaims.put("iat", 1516239022L);
bodyClaims.put("exp", 1516239122L);
JwtClaims claims = new JwtClaims(bodyClaims);
// 生成秘钥
Key key = MacProvider.generateKey();
// 创建JWT令牌
JwtToken jwtToken = new JwtToken(header, claims, key);
// 将令牌序列化
String serializedJwtToken = jwtToken.serializeAndSign();
3.2 验证 JWT 令牌
下面是使用 Java 验证 JWT 令牌的示例:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
// 解析JWT令牌,获取头部和主体
String[] tokenPieces = token.split("\\.");
String jwtHeader = tokenPieces[0];
String jwtPayload = tokenPieces[1];
// 拼接签名字符串
String base64UrlHeader = Base64.getUrlEncoder().encodeToString(jwtHeader.getBytes("UTF-8"));
String base64UrlPayload = Base64.getUrlEncoder().encodeToString(jwtPayload.getBytes("UTF-8"));
String signatureInput = base64UrlHeader + "." + base64UrlPayload;
// 验证签名
byte[] secretBytes = "a_secret".getBytes("UTF-8");
SignatureAlgorithm algorithm = SignatureAlgorithm.forName("HS256");
Key key = new SecretKeySpec(secretBytes, algorithm.getJcaName());
JwtParser jwtParser = Jwts.parserBuilder()
.setSigningKey(key)
.build();
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
// 获取 JWT 令牌中的主体
Claims claims = claimsJws.getBody();
4. 结论
使用公钥字符串验证和解析JWT令牌可以为您的 Web 应用程序提供更高的安全性。当令牌是在不同站点或服务器之间传输时,这种额外的安全性特别重要。
除了使用公钥验证和解析 JWT 令牌,还可以将令牌保存在使用安全存储库的安全服务器上,以获取最佳安全性。如果您的应用程序仅在本地运行,则可以考虑将 JWT 令牌保存在环境变量中。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java jwt使用公钥字符串验证解析token锁方法详解 - Python技术站