…
安装 openssl 服务,执行如下指令生成密钥对。
# 创建私钥
openssl genrsa -out rsa_private.pem 2048
# 创建公钥
openssl rsa -in rsa_private.pem -outform PEM -pubout -out rsa_public.pem
将创建好的密钥对放到 resources/crt 目录下,读取私钥进行签名,读取公钥进行验签。可自定义 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 sun.security.util.DerInputStream;
import sun.security.util.DerValue;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.RSAPrivateCrtKeySpec;
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) throws Exception {
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 = getRSAPrivateKey();
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 = getRSAPublicKey();
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 = getRSAPublicKey();
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 getRSAPrivateKey() {
try {
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("crt/rsa_private.pem");
String privateKeyBase64 = IOUtils.toString(inputStream, "UTF-8");
String privateKeyPEM = privateKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
.replaceAll("\\-*END.*KEY\\-*", "")
.replaceAll("\r", "")
.replaceAll("\n", "");
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
DerInputStream derReader = new DerInputStream(encoded);
DerValue[] seq = derReader.getSequence(0);
if (seq.length < 9) {
throw new GeneralSecurityException("Could not read private key");
}
// skip version seq[0];
BigInteger modulus = seq[1].getBigInteger();
BigInteger publicExp = seq[2].getBigInteger();
BigInteger privateExp = seq[3].getBigInteger();
BigInteger primeP = seq[4].getBigInteger();
BigInteger primeQ = seq[5].getBigInteger();
BigInteger expP = seq[6].getBigInteger();
BigInteger expQ = seq[7].getBigInteger();
BigInteger crtCoeff = seq[8].getBigInteger();
RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, primeP, primeQ, expP, expQ, crtCoeff);
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 = Thread.currentThread().getContextClassLoader().getResourceAsStream("crt/rsa_public.pem");
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;
}
}
…
安装 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
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;
}
}