JWT自定义SM4加密算法

一、引入依赖

<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);
}

 六、结果

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
JWT(JSON Web Token)是一种用于在网络应用之间安全传输信息的开放标准。它由三个部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。JWT的签名算法有多种选择,其中包括一些自定义的签名算法。 一种自定义的签名算法是基于EdDSA(Edwards-curve Digital Signature Algorithm)的确定性签名。使用EdDSA签名的JWT具有确定性签名,这意味着相同的JWT标头和有效负载将始终生成相同的签名。这种算法解决了依赖随机nonce值来保护私钥的问题,并且被一些JOSE和JWT的批评者推荐。 另一种自定义的签名算法是基于RSASSA-PKCS1-v1_5的确定性签名。也就是说,使用RSASSA-PKCS1-v1_5签名的JWT具有确定性签名,相同的JWT标头和有效负载将始终生成相同的签名。 此外,还有一种自定义的签名算法是基于ECDSA(Elliptic Curve Digital Signature Algorithm)的概率签名。使用ECDSA签名的JWT具有概率性签名,这意味着相同的JWT标头和有效负载将生成不同的签名。然而,ECDSA的随机生成对签名的安全性至关重要。 总结起来,JWT自定义签名算法包括确定性签名算法(如EdDSA和RSASSA-PKCS1-v1_5)和概率性签名算法(如ECDSA)。根据具体的安全需求和性能要求,可以选择不同的签名算法来保护JWT的完整性和安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值