一、引入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
</dependency>
二、编写SM4加解密工具类
/**
* SM4 对称加密,密钥长度和分组长度均为128位
* 国密算法
* @author linhm
*/
public class Sm4Util {
/**
* 加密
* @param data
* @return
*/
public static String encrypt(String data,byte[] secret){
SM4 sm4 = SmUtil.sm4(secret);
return sm4.encryptHex(data);
}
/**
* 解密
* @param data
* @return
*/
public static String decrypt(String data,byte[] secret){
SM4 sm4 = SmUtil.sm4(secret);
return sm4.decryptStr(data);
}
}
三、扩展jwt的Algorithm类
/**
* Author: linhm
* Description:jwt扩展Sm4国密算法
*/
public class Sm4Algorithm extends Algorithm {
private final byte[] secret;
protected Sm4Algorithm(String secret) {
super("Sm4", "Sm4");
this.secret = getSecretBytes(secret);
}
/**
* jwt校验
* @param jwt
* @throws SignatureVerificationException
*/
@Override
public void verify(DecodedJWT jwt) throws SignatureVerificationException {
//获取Header和payload值
byte[] headerBytes = jwt.getHeader().getBytes(StandardCharsets.UTF_8);
byte[] payloadBytes = jwt.getPayload().getBytes(StandardCharsets.UTF_8);
byte[] contentBytes = new byte[headerBytes.length + 1 + payloadBytes.length];
System.arraycopy(headerBytes, 0, contentBytes, 0, headerBytes.length);
contentBytes[headerBytes.length] = 46;
System.arraycopy(payloadBytes, 0, contentBytes, headerBytes.length + 1, payloadBytes.length);
String contentBefore = new String(contentBytes);
//获取jwt加签值并进行解密
byte[] decode = Base64.getUrlDecoder().decode(jwt.getSignature());
String data = new String(decode);
String contentAfter = Sm4Util.decrypt(data, this.secret);
//比较值是否相等
if (!contentAfter.equals(contentBefore)){
throw new RuntimeException("Token校验失败");
}
}
/**
* jwt进行sm4加密
* @param contentBytes
* @return
* @throws SignatureGenerationException
*/
@Override
public byte[] sign(byte[] contentBytes) throws SignatureGenerationException {
String data = new String(contentBytes);
String encrypt = Sm4Util.encrypt(data, this.secret);
return StrUtil.bytes(encrypt, CharsetUtil.CHARSET_UTF_8);
}
private byte[] getSecretBytes(String secret) throws IllegalArgumentException {
if (secret == null) {
throw new CupException("The Secret cannot be null");
} else {
return secret.getBytes(StandardCharsets.UTF_8);
}
}
}
四、jwt引用 Sm4Algorithm扩展类
/**
* @description jwt工具类
* @author lhm
**/
public class JwtUtils {
private static String secret ="testkey0123456789"; // 秘钥
public static String getToken()
throws Exception {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.MINUTE, 120);
// 创建JWT builder
JWTCreator.Builder builder = JWT.create();
// payload
builder.withClaim("USER_ID", "user_id");
// 指定令牌的过期时间
String token = builder.withExpiresAt(instance.getTime()).sign(new Sm4Algorithm(secret));// 签名
return token;
}
public static DecodedJWT verify(String token) {
DecodedJWT verify = null;
if (StringUtils.isEmpty(token)) {
throw new RuntimeException("token不能为空");
}
try {
// 校验token
verify = JWT.require(new Sm4Algorithm(secret)).build().verify(token);
} catch (SignatureVerificationException e) {
throw new RuntimeException("签名无效");
} catch (TokenExpiredException e) {
throw new RuntimeException("用户登录失效,请重新登录!");
} catch (AlgorithmMismatchException e) {
throw new RuntimeException("token算法不一致");
} catch (Exception e) {
throw new RuntimeException("token无效");
}
return verify;
}
}
五、测试
public static void main(String[] args) throws Exception {
String token = getToken();
System.out.println(token);
DecodedJWT verify = verify(token);
String userId = verify.getClaim("USER_ID").asString();
System.out.println(userId);
}