使用 RS256 签名
创建 RSA 密钥
安装 openssl 服务,执行如下指令生成密钥对。
# 创建私钥
openssl genrsa -out rsa_private.pem 2048
# 创建公钥
openssl rsa -in rsa_private.pem -outform PEM -pubout -out rsa_public.pem
创建和验证 JWT Token
将创建好的密钥对放到 resources/crt 目录下,读取私钥进行签名,读取公钥进行验签。可自定义 token 中携带的信息,确保自定义信息中没有敏感信息,例如密码、手机号等。
package com.uniedu.sa.questionnaire;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
public class JwtUtils {
private static final long EXPIRE = 10 * 60 * 60;
private static final String DEVICE_ID = "device_id";
private static final String PUBLIC_KEY_PATH = "/home/user/rsa_public.pem";
private static final String PRIVATE_KEY_PATH = "/home/user/rsa_private.pem";
public static void main(String[] args) {
// 代码生成密钥方式
// KeyPair keyPair = generateKeyPair(2048);
// PublicKey publicKey = keyPair.getPublic();
// PrivateKey privateKey = keyPair.getPrivate();
// 读取密钥文件方式-注意修改密钥文件目录
PublicKey publicKey = getRSAPublicKey();
PrivateKey privateKey = getRSAPrivateKey();
String token = createAccessJwtToken(privateKey, "YJ1001");
System.err.println(token);
boolean validatorToken = validatorToken(publicKey, token);
System.err.println(validatorToken);
String id = parseAccessJwtToken(publicKey, token);
System.err.println(id);
}
/**
* 生成token字符串的方法
*
* @param deviceId
* @return
*/
public static String createAccessJwtToken(PrivateKey privateKey, String deviceId) {
Claims claims = Jwts.claims().setSubject(deviceId);
claims.put(DEVICE_ID, deviceId);
String accessToken = Jwts.builder()
.setClaims(claims)
.setIssuer("User")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.signWith(SignatureAlgorithm.RS256, privateKey)
.compact();
return accessToken;
}
/**
* 判断token是否存在与有效
*
* @param accessToken
* @return
*/
public static boolean validatorToken(PublicKey publicKey, String accessToken) {
try {
if (StringUtils.isEmpty(accessToken)) {
return false;
}
Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取deviceId
*
* @param accessToken
* @return
*/
public static String parseAccessJwtToken(PublicKey publicKey, String accessToken) {
try {
if (StringUtils.isEmpty(accessToken)) {
return null;
}
Jws<Claims> jws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
Claims claims = jws.getBody();
return claims.get(DEVICE_ID, String.class);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 生成 RSA 密钥
*
* @param keysize
* @return
*/
public static KeyPair generateKeyPair(int keysize) {
try {
// 获取指定算法的密钥对生成器
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器(指定密钥长度, 使用默认的安全随机数源)
generator.initialize(keysize);
// 随机生成一对密钥(包含公钥和私钥)
return generator.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取PrivateKey对象
*
* @return
*/
private static PrivateKey getRSAPrivateKey() {
try {
InputStream inputStream = new FileInputStream(PRIVATE_KEY_PATH);
String privateKeyBase64 = IOUtils.toString(inputStream, "UTF-8");
String privateKeyPEM = privateKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
.replaceAll("\\-*END.*KEY\\-*", "")
.replaceAll("\r", "")
.replaceAll("\n", "");
Security.addProvider(new BouncyCastleProvider());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyPEM));
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取PublicKey对象
*
* @return
*/
private static PublicKey getRSAPublicKey() {
try {
InputStream inputStream = new FileInputStream(PUBLIC_KEY_PATH);
String publicKeyBase64 = IOUtils.toString(inputStream, "UTF-8");
String publicKeyPEM = publicKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
.replaceAll("\\-*END.*KEY\\-*", "")
.replaceAll("\r", "")
.replaceAll("\n", "");
Security.addProvider(new BouncyCastleProvider());
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyPEM));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
return publicKey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
使用 ES256 加密
创建 ES256 密钥
安装 openssl 服务,执行如下指令生成密钥对,这里注意需要将私钥转换为 pkcs8 格式。
# 创建私钥
openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
# 创建公钥
openssl ec -in ec_private.pem -pubout -out ec_public.pem
# 转换私钥
openssl pkcs8 -topk8 -inform PEM -outform DER -in ec_private.pem -nocrypt > ec_private_pkcs8
创建和验证 JWT Token
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.StringUtils;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
public class JwtUtils {
public static final String DEVICE_ID = "device_id";
public static final long EXPIRE = 10 * 60 * 60;
public static void main(String[] args) {
String token = createAccessJwtToken("YJ1001");
System.err.println(token);
boolean validatorToken = validatorToken(token);
System.err.println(validatorToken);
String id = parseAccessJwtToken(token);
System.err.println(id);
}
/**
* 生成token字符串的方法
*
* @param deviceId
* @return
*/
public static String createAccessJwtToken(String deviceId) {
PrivateKey privateKey = getECPrivateKey();
Claims claims = Jwts.claims().setSubject(deviceId);
claims.put(DEVICE_ID, deviceId);
String accessToken = Jwts.builder()
.setClaims(claims)
.setIssuer("User")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.signWith(SignatureAlgorithm.ES256, privateKey)
.compact();
return accessToken;
}
/**
* 判断token是否存在与有效
*
* @param accessToken
* @return
*/
public static boolean validatorToken(String accessToken) {
try {
if (StringUtils.isEmpty(accessToken)) {
return false;
}
PublicKey publicKey = getECPublicKey();
Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取deviceId
*
* @param accessToken
* @return
*/
public static String parseAccessJwtToken(String accessToken) {
try {
if (StringUtils.isEmpty(accessToken)) {
return null;
}
PublicKey publicKey = getECPublicKey();
Jws<Claims> jws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
Claims claims = jws.getBody();
return claims.get(DEVICE_ID, String.class);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取PrivateKey对象
*
* @return
*/
private static PrivateKey getECPrivateKey() {
try {
Security.addProvider(new BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "BC");
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("crt/ec_private_pkcs8");
byte[] devicePriKeybytes = IOUtils.toByteArray(inputStream);
PKCS8EncodedKeySpec devicePriKeySpec = new PKCS8EncodedKeySpec(devicePriKeybytes);
return keyFactory.generatePrivate(devicePriKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取PublicKey对象
*
* @return
*/
private static PublicKey getECPublicKey() {
try {
Security.addProvider(new BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "BC");
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("crt/ec_public.pem");
String publicKeyBase64 = IOUtils.toString(inputStream, "UTF-8");
publicKeyBase64 = publicKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
.replaceAll("\\-*END.*KEY\\-*", "")
.replaceAll("\r", "")
.replaceAll("\n", "");
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64);
X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(publicKeyBytes);
return keyFactory.generatePublic(pubX509);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}