依赖
implementation 'com.auth0:java-jwt:3.4.0'
工具类
package com.solargrids.energymonitor.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.StringUtils;
import java.util.Calendar;
import java.util.Map;
/**
* @author 1065246
* @description:
* @createTime:2023/3/2 13:35
*/
public class JWTUtil {
/**
* 签名秘钥 此签名为 pwd的sha256大写
* SecureUtil.sha256("pwd").toUpperCase()
*/
private static final String SIGN_KEY = "7D5703BFD49B6CFE16F79A8A8F539DC5E2C3A8E203F00C09538E47AE26F8B03D";
/**
* 默认的过期时间:分钟
*/
private static final Integer DEFAULT_EXPIRES = 60 * 60;
/**
* token默认的长度
*/
private static final Integer DEFAULT_TOKEN_SIZE = 3;
/**
* 生成令牌
*
* @param payload 数据正文
* @param expires 过期时间,单位(秒)
*/
public static String getToken(Map<String, String> payload, Integer expires) throws Exception {
//创建日历
Calendar instance = Calendar.getInstance();
//设置过期时间
instance.add(Calendar.SECOND, expires);
//创建jwt builder对象
JWTCreator.Builder builder = JWT.create();
//payload
payload.forEach((k, v) -> {builder.withClaim(k, v);});
//指定过期时间
String token = builder.withExpiresAt(instance.getTime())//设置加密方式
.sign(Algorithm.HMAC256(SIGN_KEY));
//返回tokean
return confoundPayload(token);
}
public static DecodedJWT verify(String token) throws TokenAuthenticationException {
try {
//解析token
String dToken = deConfoundPayload(token);
//创建返回结果
return JWT.require(Algorithm.HMAC256(SIGN_KEY)).build().verify(dToken);
} catch (JWTDecodeException jwtDecodeException) {
throw new TokenAuthenticationException(ResultEnum.TOKEN_INVALID);
} catch (SignatureVerificationException signatureVerificationException) {
throw new TokenAuthenticationException(ResultEnum.TOKEN_SIGNATURE_INVALID);
} catch (TokenExpiredException tokenExpiredException) {
throw new TokenAuthenticationException(ResultEnum.TOKEN_EXPIRED);
} catch (Exception ex) {
throw new TokenAuthenticationException(ResultEnum.TOKEN_ERROR);
}
}
/**
* 对一个base64编码进行混淆 此处还可以进行replace混淆,考虑到效率问题,这里就不做啦~
* 对于加密的思路还有位移、字符替换等~
*
* @param token 混淆payload前的token
*/
private static String confoundPayload(String token) throws Exception {
//分割token
String[] split = token.split("\\.");
//如果token不符合规范
if (split.length != DEFAULT_TOKEN_SIZE) {
throw new JWTDecodeException("签名不正确");
}
//取出payload
String payload = split[1];
//获取长度
int length = payload.length() / 2;
//指定截取点
int index = payload.length() % 2 != 0 ? length + 1 : length;
//混淆处理后的token
return split[0] + "." + reversePayload(payload, index) + "." + split[2];
}
/**
* 对一个混淆后的base编码进行解析
* Authorization: Bearer <token>
* @param token 混淆后的token
*/
private static String deConfoundPayload(String token) throws Exception {
if(StringUtils.isEmpty(token)){
throw new JWTDecodeException("you have no permission with token,please login!");
}
//分割token
String[] split = token.split("\\.");
//如果token不符合规范
if (split.length != DEFAULT_TOKEN_SIZE) {
throw new JWTDecodeException("you token is valid");
}
//取出payload
String payload = split[1];
//返回解析后的token
return split[0] + "." + reversePayload(payload, payload.length() / 2) + "." + split[2];
}
/**
* 将md5编码位移
*
* @param payload payload编码
* @param index 位移处
*/
private static String reversePayload(String payload, Integer index) {
return payload.substring(index) + payload.substring(0, index);
}
}