mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-10-27 02:59:02 +08:00
sa-token-jwt 模块改为 Util + Template 形式,方便针对部分代码重写。
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
package cn.dev33.satoken.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtException;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtExceptionCode;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTException;
|
||||
|
||||
/**
|
||||
* jwt 操作模板方法封装
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaJwtTemplate {
|
||||
|
||||
/**
|
||||
* key:账号类型
|
||||
*/
|
||||
public static final String LOGIN_TYPE = "loginType";
|
||||
|
||||
/**
|
||||
* key:账号id
|
||||
*/
|
||||
public static final String LOGIN_ID = "loginId";
|
||||
|
||||
/**
|
||||
* key:登录设备类型
|
||||
*/
|
||||
public static final String DEVICE = "device";
|
||||
|
||||
/**
|
||||
* key:有效截止期 (时间戳)
|
||||
*/
|
||||
public static final String EFF = "eff";
|
||||
|
||||
/**
|
||||
* key:乱数 ( 混入随机字符串,防止每次生成的 token 都是一样的 )
|
||||
*/
|
||||
public static final String RN_STR = "rnStr";
|
||||
|
||||
/**
|
||||
* 当有效期被设为此值时,代表永不过期
|
||||
*/
|
||||
public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE;
|
||||
|
||||
/**
|
||||
* 表示一个值不存在
|
||||
*/
|
||||
public static final long NOT_VALUE_EXPIRE = SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
|
||||
// ------ 创建
|
||||
|
||||
/**
|
||||
* 创建 jwt (简单方式)
|
||||
* @param loginType 登录类型
|
||||
* @param loginId 账号id
|
||||
* @param extraData 扩展数据
|
||||
* @param keyt 秘钥
|
||||
* @return jwt-token
|
||||
*/
|
||||
public String createToken(String loginType, Object loginId, Map<String, Object> extraData, String keyt) {
|
||||
|
||||
// 构建
|
||||
JWT jwt = JWT.create()
|
||||
.setPayload(LOGIN_TYPE, loginType)
|
||||
.setPayload(LOGIN_ID, loginId)
|
||||
.setPayload(RN_STR, SaFoxUtil.getRandomString(32))
|
||||
.addPayloads(extraData)
|
||||
;
|
||||
|
||||
// 返回
|
||||
return generateToken(jwt, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 jwt (全参数方式)
|
||||
* @param loginType 账号类型
|
||||
* @param loginId 账号id
|
||||
* @param device 设备类型
|
||||
* @param timeout token有效期 (单位 秒)
|
||||
* @param extraData 扩展数据
|
||||
* @param keyt 秘钥
|
||||
* @return jwt-token
|
||||
*/
|
||||
public String createToken(String loginType, Object loginId, String device,
|
||||
long timeout, Map<String, Object> extraData, String keyt) {
|
||||
|
||||
// 计算有效期
|
||||
long effTime = timeout;
|
||||
if(timeout != NEVER_EXPIRE) {
|
||||
effTime = timeout * 1000 + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// 创建
|
||||
JWT jwt = JWT.create()
|
||||
.setPayload(LOGIN_TYPE, loginType)
|
||||
.setPayload(LOGIN_ID, loginId)
|
||||
.setPayload(DEVICE, device)
|
||||
.setPayload(EFF, effTime)
|
||||
.setPayload(RN_STR, SaFoxUtil.getRandomString(32))
|
||||
.addPayloads(extraData);
|
||||
|
||||
// 返回
|
||||
return generateToken(jwt, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为 JWT 对象和 keyt 秘钥,生成 token 字符串
|
||||
* @param jwt JWT构建对象
|
||||
* @return 根据 JWT 对象和 keyt 秘钥,生成的 token 字符串
|
||||
*/
|
||||
public String generateToken (JWT jwt, String keyt) {
|
||||
return jwt.setKey(keyt.getBytes()).sign();
|
||||
}
|
||||
|
||||
// ------ 解析
|
||||
|
||||
/**
|
||||
* jwt 解析
|
||||
* @param token Jwt-Token值
|
||||
* @param loginType 登录类型
|
||||
* @param keyt 秘钥
|
||||
* @param isCheckTimeout 是否校验 timeout 字段
|
||||
* @return 解析后的jwt 对象
|
||||
*/
|
||||
public JWT parseToken(String token, String loginType, String keyt, boolean isCheckTimeout) {
|
||||
|
||||
// 秘钥不可以为空
|
||||
if(keyt == null) {
|
||||
throw new SaJwtException("请配置 jwt 秘钥");
|
||||
}
|
||||
|
||||
// 如果token为null
|
||||
if(token == null) {
|
||||
throw new SaJwtException("jwt 字符串不可为空");
|
||||
}
|
||||
|
||||
// 解析
|
||||
JWT jwt = null;
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
throw new SaJwtException("jwt 解析失败:" + token, e).setCode(SaJwtExceptionCode.CODE_40101);
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 校验 Token 签名
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
throw new SaJwtException("jwt 签名无效:" + token).setCode(SaJwtExceptionCode.CODE_40102);
|
||||
};
|
||||
|
||||
// 校验 loginType
|
||||
if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) {
|
||||
throw new SaJwtException("jwt loginType 无效:" + token).setCode(SaJwtExceptionCode.CODE_40103);
|
||||
}
|
||||
|
||||
// 校验 Token 有效期
|
||||
if(isCheckTimeout) {
|
||||
Long effTime = payloads.getLong(EFF, 0L);
|
||||
if(effTime != NEVER_EXPIRE) {
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
throw new SaJwtException("jwt 已过期:" + token).setCode(SaJwtExceptionCode.CODE_40104);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 数据载荷 (校验 sign、loginType、timeout)
|
||||
* @param token token值
|
||||
* @param loginType 登录类型
|
||||
* @param keyt 秘钥
|
||||
* @return 载荷
|
||||
*/
|
||||
public JSONObject getPayloads(String token, String loginType, String keyt) {
|
||||
return parseToken(token, loginType, keyt, true).getPayloads();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 数据载荷 (校验 sign、loginType,不校验 timeout)
|
||||
* @param token token值
|
||||
* @param loginType 登录类型
|
||||
* @param keyt 秘钥
|
||||
* @return 载荷
|
||||
*/
|
||||
public JSONObject getPayloadsNotCheck(String token, String loginType, String keyt) {
|
||||
return parseToken(token, loginType, keyt, false).getPayloads();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 代表的账号id
|
||||
* @param token Token值
|
||||
* @param loginType 登录类型
|
||||
* @param keyt 秘钥
|
||||
* @return 值
|
||||
*/
|
||||
public Object getLoginId(String token, String loginType, String keyt) {
|
||||
return getPayloads(token, loginType, keyt).get(LOGIN_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 代表的账号id (未登录时返回null)
|
||||
* @param token Token值
|
||||
* @param loginType 登录类型
|
||||
* @param keyt 秘钥
|
||||
* @return 值
|
||||
*/
|
||||
public Object getLoginIdOrNull(String token, String loginType, String keyt) {
|
||||
try {
|
||||
return getPayloads(token, loginType, keyt).get(LOGIN_ID);
|
||||
} catch (SaJwtException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 剩余有效期
|
||||
* @param token JwtToken值
|
||||
* @param loginType 登录类型
|
||||
* @param keyt 秘钥
|
||||
* @return 值
|
||||
*/
|
||||
public long getTimeout(String token, String loginType, String keyt) {
|
||||
|
||||
// 如果token为null
|
||||
if(token == null) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 取出数据
|
||||
JWT jwt = null;
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
// 解析失败
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 如果签名无效
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
};
|
||||
|
||||
// 如果 loginType 无效
|
||||
if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 如果被设置为:永不过期
|
||||
Long effTime = payloads.get(EFF, Long.class);
|
||||
if(effTime == NEVER_EXPIRE) {
|
||||
return NEVER_EXPIRE;
|
||||
}
|
||||
// 如果已经超时
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 计算timeout (转化为以秒为单位的有效时间)
|
||||
return (effTime - System.currentTimeMillis()) / 1000;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,9 @@
|
||||
package cn.dev33.satoken.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtException;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtExceptionCode;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTException;
|
||||
|
||||
/**
|
||||
* jwt 操作工具类封装
|
||||
@@ -18,40 +12,64 @@ import cn.hutool.jwt.JWTException;
|
||||
*/
|
||||
public class SaJwtUtil {
|
||||
|
||||
/**
|
||||
* 底层 saJwtTemplate 对象
|
||||
*/
|
||||
public static SaJwtTemplate saJwtTemplate = new SaJwtTemplate();
|
||||
|
||||
/**
|
||||
* 获取底层 saJwtTemplate 对象
|
||||
* @return /
|
||||
*/
|
||||
public static SaJwtTemplate getSaJwtTemplate() {
|
||||
return saJwtTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置底层 saJwtTemplate 对象
|
||||
* @param saJwtTemplate /
|
||||
*/
|
||||
public static void setSaJwtTemplate(SaJwtTemplate saJwtTemplate) {
|
||||
SaJwtUtil.saJwtTemplate = saJwtTemplate;
|
||||
}
|
||||
|
||||
// 常量
|
||||
|
||||
|
||||
/**
|
||||
* key:账号类型
|
||||
*/
|
||||
public static final String LOGIN_TYPE = "loginType";
|
||||
public static final String LOGIN_TYPE = SaJwtTemplate.LOGIN_TYPE;
|
||||
|
||||
/**
|
||||
* key:账号id
|
||||
*/
|
||||
public static final String LOGIN_ID = "loginId";
|
||||
public static final String LOGIN_ID = SaJwtTemplate.LOGIN_ID;
|
||||
|
||||
/**
|
||||
* key:登录设备类型
|
||||
*/
|
||||
public static final String DEVICE = "device";
|
||||
public static final String DEVICE = SaJwtTemplate.DEVICE;
|
||||
|
||||
/**
|
||||
* key:有效截止期 (时间戳)
|
||||
*/
|
||||
public static final String EFF = "eff";
|
||||
public static final String EFF = SaJwtTemplate.EFF;
|
||||
|
||||
/**
|
||||
* key:乱数 ( 混入随机字符串,防止每次生成的 token 都是一样的 )
|
||||
*/
|
||||
public static final String RN_STR = "rnStr";
|
||||
public static final String RN_STR = SaJwtTemplate.RN_STR;
|
||||
|
||||
/**
|
||||
* 当有效期被设为此值时,代表永不过期
|
||||
*/
|
||||
public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE;
|
||||
public static final long NEVER_EXPIRE = SaJwtTemplate.NEVER_EXPIRE;
|
||||
|
||||
/**
|
||||
* 表示一个值不存在
|
||||
*/
|
||||
public static final long NOT_VALUE_EXPIRE = SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
public static final long NOT_VALUE_EXPIRE = SaJwtTemplate.NOT_VALUE_EXPIRE;
|
||||
|
||||
// ------ 创建
|
||||
|
||||
@@ -64,18 +82,7 @@ public class SaJwtUtil {
|
||||
* @return jwt-token
|
||||
*/
|
||||
public static String createToken(String loginType, Object loginId, Map<String, Object> extraData, String keyt) {
|
||||
|
||||
// 构建
|
||||
String token = JWT.create()
|
||||
.setPayload(LOGIN_TYPE, loginType)
|
||||
.setPayload(LOGIN_ID, loginId)
|
||||
.setPayload(RN_STR, SaFoxUtil.getRandomString(32))
|
||||
.addPayloads(extraData)
|
||||
.setKey(keyt.getBytes())
|
||||
.sign();
|
||||
|
||||
// 返回
|
||||
return token;
|
||||
return saJwtTemplate.createToken(loginType, loginId, extraData, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,26 +97,18 @@ public class SaJwtUtil {
|
||||
*/
|
||||
public static String createToken(String loginType, Object loginId, String device,
|
||||
long timeout, Map<String, Object> extraData, String keyt) {
|
||||
|
||||
// 计算有效期
|
||||
long effTime = timeout;
|
||||
if(timeout != NEVER_EXPIRE) {
|
||||
effTime = timeout * 1000 + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// 创建
|
||||
JWT jwt = JWT.create()
|
||||
.setPayload(LOGIN_TYPE, loginType)
|
||||
.setPayload(LOGIN_ID, loginId)
|
||||
.setPayload(DEVICE, device)
|
||||
.setPayload(EFF, effTime)
|
||||
.setPayload(RN_STR, SaFoxUtil.getRandomString(32))
|
||||
.addPayloads(extraData);
|
||||
|
||||
// 返回
|
||||
return jwt.setKey(keyt.getBytes()).sign();
|
||||
return saJwtTemplate.createToken(loginType, loginId, device, timeout, extraData, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为 JWT 对象和 keyt 秘钥,生成 token 字符串
|
||||
* @param jwt JWT构建对象
|
||||
* @return 根据 JWT 对象和 keyt 秘钥,生成的 token 字符串
|
||||
*/
|
||||
public static String generateToken (JWT jwt, String keyt) {
|
||||
return saJwtTemplate.generateToken(jwt, keyt);
|
||||
}
|
||||
|
||||
// ------ 解析
|
||||
|
||||
/**
|
||||
@@ -121,49 +120,7 @@ public class SaJwtUtil {
|
||||
* @return 解析后的jwt 对象
|
||||
*/
|
||||
public static JWT parseToken(String token, String loginType, String keyt, boolean isCheckTimeout) {
|
||||
|
||||
// 秘钥不可以为空
|
||||
if(keyt == null) {
|
||||
throw new SaJwtException("请配置 jwt 秘钥");
|
||||
}
|
||||
|
||||
// 如果token为null
|
||||
if(token == null) {
|
||||
throw new SaJwtException("jwt 字符串不可为空");
|
||||
}
|
||||
|
||||
// 解析
|
||||
JWT jwt = null;
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
throw new SaJwtException("jwt 解析失败:" + token, e).setCode(SaJwtExceptionCode.CODE_40101);
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 校验 Token 签名
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
throw new SaJwtException("jwt 签名无效:" + token).setCode(SaJwtExceptionCode.CODE_40102);
|
||||
};
|
||||
|
||||
// 校验 loginType
|
||||
if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) {
|
||||
throw new SaJwtException("jwt loginType 无效:" + token).setCode(SaJwtExceptionCode.CODE_40103);
|
||||
}
|
||||
|
||||
// 校验 Token 有效期
|
||||
if(isCheckTimeout) {
|
||||
Long effTime = payloads.getLong(EFF, 0L);
|
||||
if(effTime != NEVER_EXPIRE) {
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
throw new SaJwtException("jwt 已过期:" + token).setCode(SaJwtExceptionCode.CODE_40104);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回
|
||||
return jwt;
|
||||
return saJwtTemplate.parseToken(token, loginType, keyt, isCheckTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,7 +131,7 @@ public class SaJwtUtil {
|
||||
* @return 载荷
|
||||
*/
|
||||
public static JSONObject getPayloads(String token, String loginType, String keyt) {
|
||||
return parseToken(token, loginType, keyt, true).getPayloads();
|
||||
return saJwtTemplate.getPayloads(token, loginType, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +142,7 @@ public class SaJwtUtil {
|
||||
* @return 载荷
|
||||
*/
|
||||
public static JSONObject getPayloadsNotCheck(String token, String loginType, String keyt) {
|
||||
return parseToken(token, loginType, keyt, false).getPayloads();
|
||||
return saJwtTemplate.getPayloadsNotCheck(token, loginType, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +153,7 @@ public class SaJwtUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static Object getLoginId(String token, String loginType, String keyt) {
|
||||
return getPayloads(token, loginType, keyt).get(LOGIN_ID);
|
||||
return saJwtTemplate.getLoginId(token, loginType, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,11 +164,7 @@ public class SaJwtUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static Object getLoginIdOrNull(String token, String loginType, String keyt) {
|
||||
try {
|
||||
return getPayloads(token, loginType, keyt).get(LOGIN_ID);
|
||||
} catch (SaJwtException e) {
|
||||
return null;
|
||||
}
|
||||
return saJwtTemplate.getLoginIdOrNull(token, loginType, keyt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,45 +175,7 @@ public class SaJwtUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static long getTimeout(String token, String loginType, String keyt) {
|
||||
|
||||
// 如果token为null
|
||||
if(token == null) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 取出数据
|
||||
JWT jwt = null;
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
// 解析失败
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 如果签名无效
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
};
|
||||
|
||||
// 如果 loginType 无效
|
||||
if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 如果被设置为:永不过期
|
||||
Long effTime = payloads.get(EFF, Long.class);
|
||||
if(effTime == NEVER_EXPIRE) {
|
||||
return NEVER_EXPIRE;
|
||||
}
|
||||
// 如果已经超时
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
return NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 计算timeout (转化为以秒为单位的有效时间)
|
||||
return (effTime - System.currentTimeMillis()) / 1000;
|
||||
return saJwtTemplate.getTimeout(token, loginType, keyt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user