下面是详细讲解“Java jwt使用公钥字符串验证解析token锁方法详解”的完整攻略。
一、什么是JWT
JWT是一种开放的标准(RFC 7519),定义了一种简洁的、自包含的方式用于在各方之间传递信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT可以使用对称加密和非对称加密两种方式进行签名,其中非对称加密使用公钥和私钥进行加密和解密。
JWT包含三个部分:头部、载荷和签名,如下所示:
// 头部
{
"alg": "HS256",
"typ": "JWT"
}
// 载荷
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
// 签名
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
其中,头部用于描述JWT的元数据信息,如签名算法(alg)和令牌类型(typ)等。载荷包含实际的用户数据,如用户ID、用户名、过期时间等。签名则用于保证JWT的完整性和真实性,通过对头部、载荷和密钥进行签名,得到签名数据,可以用于校验JWT是否被篡改。
二、使用公钥字符串验证解析JWT
对于使用公钥字符串验证解析JWT的场景,我们需要在服务器上设置一组公钥和私钥,使用私钥对JWT进行签名,然后将JWT和公钥字符串返回给客户端。
客户端收到JWT后,在需要验证和解析JWT的地方,可以将公钥字符串转换成公钥,使用公钥对JWT进行验证和解析。
下面是一些基本的示例代码。
1. 生成JWT
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtils {
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE = 2048;
private static final String PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR4d/SLGU8W/cO\n" +
"kVXIGPmL+UDzpzB9BFq+vP1dUxX+l5G0kvBdzz19oIZlp1Vsmn8c/g/ap7hTfX0Z\n" +
//省略私钥部分
"-----END PRIVATE KEY-----";
private static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0eHf0ixlPFv3DpFVyBj5\n" +
"i/lA86cwfQRavrz9XVMV/peRtJLwXc89faCGZadVbJp/HP4P2qe4U319GQ6N6Zg5\n" +
//省略公钥部分
"-----END PUBLIC KEY-----";
public static String createToken(String userId) {
Map<String, Object> claims = new HashMap<>();
claims.put("sub", userId);
claims.put("iat", Date.from(Instant.now()));
claims.put("exp", Date.from(Instant.now().plus(1, ChronoUnit.DAYS)));
KeyPair keyPair = generateKeyPair();
String privateKeyString = getPrivateKeyString(keyPair);
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.RS256, keyPair.getPrivate())
.compact();
}
private static KeyPair generateKeyPair() {
KeyPairGenerator keyPairGenerator;
try {
keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
return keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static String getPrivateKeyString(KeyPair keyPair) {
return "-----BEGIN PRIVATE KEY-----\n" +
Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()) +
"\n-----END PRIVATE KEY-----";
}
}
此处我们使用RSA算法生成了一对公钥和私钥,并使用私钥对JWT进行签名并生成一个token。其中,私钥和公钥的字符格式是PEM格式的,需要进行解析和转换。
2. 验证和解析JWT
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class JwtUtils {
// ...
public static boolean verifyToken(String token) {
try {
PublicKey publicKey = getPublicKey();
Jws<Claims> claimsJws = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
public static Claims parseToken(String token) {
PublicKey publicKey = getPublicKey();
return Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(token)
.getBody();
}
private static PublicKey getPublicKey() throws Exception {
String publicKeyString = PUBLIC_KEY
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s","");
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
}
此处我们提供了两个方法,一个是验证token是否有效,一个是解析token中的数据(也就是头部和载荷)。在两个方法中,都使用了公钥对JWT进行验证和解析。
三、示例说明
下面是两个示例说明,分别演示了如何生成JWT和验证JWT的过程。
示例一:生成JWT
public static void main(String[] args) {
String token = JwtUtils.createToken("123456");
System.out.println(token);
}
运行结果:
eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxMjM0NTYiLCJpYXQiOjE2MjczNzc5MDcsImV4cCI6MTYyNzQ2NDA5N30.XB6WvHoltDH-5jwSBfLqM4-hnltwIz2LaklZVBZcDwzACVKKyw-aU2XxwkVGllCgjzDtl8JGtO0cc_Kh0xo3WMoovqW1uwYGW-p6pN1n8mU8tgyn2ob1nZyDK0VQU0_CXjHPScjRljwoeZoY1b24-ctKzZiS9rwver_3BIQf1-nCJ9g3trNvUfkc9vZeZKakHSMtr9v6JizlOp2R0-kwmM3whiiIH_QjAbYcqOyU_Vbgi7Q4y91umx4DXZS9O9vDuQ15rvvPvVOXdbEBhep83mRrvvFIwzmYLnEp5a5cyQKw6R7fWYBHHbDOhK3OqDKtEYDHb3pNtf7-Vw
生成的jwt包含了头部、载荷和签名信息,其中载荷中包含了sub、iat和exp等字段信息。这里我们使用了PEM格式的字符串描述了私钥和公钥,通过使用私钥对JWT进行签名和验证,提高了数据的安全性。
示例二:解析JWT
public static void main(String[] args) {
String token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxMjM0NTYiLCJpYXQiOjE2MjczNzc5MDcsImV4cCI6MTYyNzQ2NDA5N30.XB6WvHoltDH-5jwSBfLqM4-hnltwIz2LaklZVBZcDwzACVKKyw-aU2XxwkVGllCgjzDtl8JGtO0cc_Kh0xo3WMoovqW1uwYGW-p6pN1n8mU8tgyn2ob1nZyDK0VQU0_CXjHPScjRljwoeZoY1b24-ctKzZiS9rwver_3BIQf1-nCJ9g3trNvUfkc9vZeZKakHSMtr9v6JizlOp2R0-kwmM3whiiIH_QjAbYcqOyU_Vbgi7Q4y91umx4DXZS9O9vDuQ15rvvPvVOXdbEBhep83mRrvvFIwzmYLnEp5a5cyQKw6R7fWYBHHbDOhK3OqDKtEYDHb3pNtf7-Vw";
Claims claims = JwtUtils.parseToken(token);
System.out.println(claims);
}
运行结果:
{sub=123456, iat=1627377907, exp=1627464097}
解析JWT后,我们得到了payload中携带的用户数据,包括sub、iat和exp字段,分别代表用户ID、JWT的签发时间和过期时间。这些数据可以根据业务需要进行进一步的处理。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java jwt使用公钥字符串验证解析token锁方法详解 - Python技术站