mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-10-27 02:59:02 +08:00
v1.27.1 新增jwt集成插件
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
package cn.dev33.satoken.jwt;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
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 SaJwtUtil {
|
||||
|
||||
/**
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* 当有效期被设为此值时,代表永不过期
|
||||
*/
|
||||
public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE;
|
||||
|
||||
|
||||
/**
|
||||
* 创建 jwt (简单方式)
|
||||
* @param loginId 账号id
|
||||
* @param keyt 秘钥
|
||||
* @return jwt-token
|
||||
*/
|
||||
public static String createToken(Object loginId, String keyt) {
|
||||
|
||||
// 秘钥不可以为空
|
||||
SaTokenException.throwByNull(keyt, "请配置jwt秘钥");
|
||||
|
||||
// 构建
|
||||
String token = JWT.create()
|
||||
.setPayload(LOGIN_ID, loginId)
|
||||
// 混入随机字符
|
||||
.setPayload("rn", SaFoxUtil.getRandomString(32))
|
||||
.setKey(keyt.getBytes())
|
||||
.sign();
|
||||
|
||||
// 返回
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 jwt (全参数方式)
|
||||
* @param loginType 账号类型
|
||||
* @param loginId 账号id
|
||||
* @param device 设备标识
|
||||
* @param timeout token有效期 (单位 秒)
|
||||
* @param keyt 秘钥
|
||||
* @return jwt-token
|
||||
*/
|
||||
public static String createToken(String loginType, Object loginId, String device, long timeout, String keyt) {
|
||||
|
||||
// 秘钥不可以为空
|
||||
SaTokenException.throwByNull(keyt, "请配置jwt秘钥");
|
||||
|
||||
// 计算有效期
|
||||
long effTime = timeout;
|
||||
if(timeout != NEVER_EXPIRE) {
|
||||
effTime = timeout * 1000 + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// 构建
|
||||
String token = JWT.create()
|
||||
.setPayload(LOGIN_TYPE, loginType)
|
||||
.setPayload(LOGIN_ID, loginId)
|
||||
.setPayload(DEVICE, device)
|
||||
.setPayload(EFF, effTime)
|
||||
.setKey(keyt.getBytes())
|
||||
.sign();
|
||||
|
||||
// 返回
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* jwt 解析(校验签名和密码)
|
||||
* @param token Jwt-Token值
|
||||
* @param keyt 秘钥
|
||||
* @return 解析后的jwt 对象
|
||||
*/
|
||||
public static JWT parseToken(String token, String keyt) {
|
||||
|
||||
// 如果token为null
|
||||
if(token == null) {
|
||||
throw NotLoginException.newInstance(null, NotLoginException.NOT_TOKEN);
|
||||
}
|
||||
|
||||
// 解析
|
||||
JWT jwt = null;
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
// 解析失败
|
||||
throw NotLoginException.newInstance(null, NotLoginException.INVALID_TOKEN, token);
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 校验 Token 签名
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
throw NotLoginException.newInstance(payloads.getStr(LOGIN_TYPE), NotLoginException.INVALID_TOKEN, token);
|
||||
};
|
||||
|
||||
// 校验 Token 有效期
|
||||
Long effTime = payloads.getLong(EFF, 0L);
|
||||
if(effTime != NEVER_EXPIRE) {
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
throw NotLoginException.newInstance(payloads.getStr(LOGIN_TYPE), NotLoginException.TOKEN_TIMEOUT, token);
|
||||
}
|
||||
}
|
||||
|
||||
// 返回
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 数据载荷 (校验签名和密码)
|
||||
* @param token token值
|
||||
* @param keyt 秘钥
|
||||
* @return 载荷
|
||||
*/
|
||||
public static JSONObject getPayloads(String token, String keyt) {
|
||||
return parseToken(token, keyt).getPayloads();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 数据载荷 (不校验签名和密码)
|
||||
* @param token token值
|
||||
* @param keyt 秘钥
|
||||
* @return 载荷
|
||||
*/
|
||||
public static JSONObject getPayloadsNotCheck(String token, String keyt) {
|
||||
try {
|
||||
JWT jwt = JWT.of(token);
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
return payloads;
|
||||
} catch (JWTException e) {
|
||||
return new JSONObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 代表的账号id
|
||||
* @param token Token值
|
||||
* @param keyt 秘钥
|
||||
* @return 值
|
||||
*/
|
||||
public static Object getLoginId(String token, String keyt) {
|
||||
return getPayloads(token, keyt).get(LOGIN_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 代表的账号id (未登录时返回null)
|
||||
* @param token Token值
|
||||
* @param keyt 秘钥
|
||||
* @return 值
|
||||
*/
|
||||
public static Object getLoginIdOrNull(String token, String keyt) {
|
||||
try {
|
||||
return getPayloads(token, keyt).get(LOGIN_ID);
|
||||
} catch (NotLoginException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 jwt 剩余有效期
|
||||
* @param token JwtToken值
|
||||
* @param keyt 秘钥
|
||||
* @return 值
|
||||
*/
|
||||
public static long getTimeout(String token, String keyt) {
|
||||
|
||||
// 如果token为null
|
||||
if(token == null) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 取出数据
|
||||
JWT jwt = null;
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
// 解析失败
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 如果签名无效
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
};
|
||||
|
||||
// 如果被设置为:永不过期
|
||||
Long effTime = payloads.get(EFF, Long.class);
|
||||
if(effTime == NEVER_EXPIRE) {
|
||||
return NEVER_EXPIRE;
|
||||
}
|
||||
// 如果已经超时
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
}
|
||||
|
||||
// 计算timeout (转化为以秒为单位的有效时间)
|
||||
return (effTime - System.currentTimeMillis()) / 1000;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package cn.dev33.satoken.jwt;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token 整合 jwt -- stateless 无状态
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class StpLogicJwtForStateless extends StpLogic {
|
||||
|
||||
/**
|
||||
* 异常描述
|
||||
*/
|
||||
public static final String ERROR_MESSAGE = "This API is disabled";
|
||||
|
||||
/**
|
||||
* 初始化StpLogic, 并指定账号类型
|
||||
* @param loginType 账号体系标识
|
||||
*/
|
||||
public StpLogicJwtForStateless() {
|
||||
super(StpUtil.TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化StpLogic, 并指定账号类型
|
||||
* @param loginType 账号体系标识
|
||||
*/
|
||||
public StpLogicJwtForStateless(String loginType) {
|
||||
super(loginType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取jwt秘钥
|
||||
* @return /
|
||||
*/
|
||||
public String jwtSecretKey() {
|
||||
return getConfig().getJwtSecretKey();
|
||||
}
|
||||
|
||||
//
|
||||
// ------ 重写方法
|
||||
//
|
||||
|
||||
// ------------------- 获取token 相关 -------------------
|
||||
|
||||
/**
|
||||
* 创建一个TokenValue
|
||||
*/
|
||||
@Override
|
||||
public String createTokenValue(Object loginId) {
|
||||
return SaJwtUtil.createToken(loginId, jwtSecretKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的Token信息
|
||||
* @return token信息
|
||||
*/
|
||||
@Override
|
||||
public SaTokenInfo getTokenInfo() {
|
||||
SaTokenInfo info = new SaTokenInfo();
|
||||
info.tokenName = getTokenName();
|
||||
info.tokenValue = getTokenValue();
|
||||
info.isLogin = isLogin();
|
||||
info.loginId = getLoginIdDefaultNull();
|
||||
info.loginType = getLoginType();
|
||||
info.tokenTimeout = getTokenTimeout();
|
||||
info.sessionTimeout = SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
info.tokenSessionTimeout = SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
info.tokenActivityTimeout = SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
info.loginDevice = getLoginDevice();
|
||||
return info;
|
||||
}
|
||||
|
||||
// ------------------- 登录相关操作 -------------------
|
||||
|
||||
/**
|
||||
* 会话登录,并指定所有登录参数Model
|
||||
*/
|
||||
@Override
|
||||
public void login(Object id, SaLoginModel loginModel) {
|
||||
|
||||
SaTokenException.throwByNull(id, "账号id不能为空");
|
||||
|
||||
// ------ 1、初始化 loginModel
|
||||
loginModel.build(getConfig());
|
||||
|
||||
// ------ 2、生成一个token
|
||||
String tokenValue = SaJwtUtil.createToken(
|
||||
loginType,
|
||||
id,
|
||||
loginModel.getDeviceOrDefalut(),
|
||||
loginModel.getTimeout(),
|
||||
jwtSecretKey()
|
||||
);
|
||||
|
||||
// 3、在当前会话写入tokenValue
|
||||
setTokenValue(tokenValue, loginModel.getCookieTimeout());
|
||||
|
||||
// $$ 通知监听器,账号xxx 登录成功
|
||||
SaManager.getSaTokenListener().doLogin(loginType, id, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定Token对应的账号id (不做任何特殊处理)
|
||||
*/
|
||||
@Override
|
||||
public String getLoginIdNotHandle(String tokenValue) {
|
||||
// 先验证 loginType,如果不符,相当于null
|
||||
String loginType = SaJwtUtil.getPayloadsNotCheck(tokenValue, jwtSecretKey()).getStr(SaJwtUtil.LOGIN_TYPE);
|
||||
if(getLoginType().equals(loginType) == false) {
|
||||
return null;
|
||||
}
|
||||
// 获取 loginId
|
||||
try {
|
||||
Object loginId = SaJwtUtil.getLoginId(tokenValue, jwtSecretKey());
|
||||
return String.valueOf(loginId);
|
||||
} catch (NotLoginException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话注销
|
||||
*/
|
||||
@Override
|
||||
public void logout() {
|
||||
// stateless模式下清除Cookie即可
|
||||
|
||||
// 如果打开了cookie模式,把cookie清除掉
|
||||
if(getConfig().getIsReadCookie() == true){
|
||||
SaManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 过期时间相关 -------------------
|
||||
|
||||
/**
|
||||
* 获取当前登录者的 token 剩余有效时间 (单位: 秒)
|
||||
*/
|
||||
@Override
|
||||
public long getTokenTimeout() {
|
||||
return SaJwtUtil.getTimeout(getTokenValue(), jwtSecretKey());
|
||||
}
|
||||
|
||||
|
||||
// ------------------- id 反查 token 相关操作 -------------------
|
||||
|
||||
/**
|
||||
* 返回当前会话的登录设备
|
||||
* @return 当前令牌的登录设备
|
||||
*/
|
||||
@Override
|
||||
public String getLoginDevice() {
|
||||
// 如果没有token,直接返回 null
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
return null;
|
||||
}
|
||||
// 如果还未登录,直接返回 null
|
||||
if(!isLogin()) {
|
||||
return null;
|
||||
}
|
||||
// 获取
|
||||
return SaJwtUtil.getPayloadsNotCheck(tokenValue, jwtSecretKey()).getStr(SaJwtUtil.DEVICE);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- Bean对象代理 -------------------
|
||||
|
||||
/**
|
||||
* 返回持久化对象
|
||||
*/
|
||||
@Override
|
||||
public SaTokenDao getSaTokenDao() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.dev33.satoken.jwt;
|
||||
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token 整合 jwt -- Token风格
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class StpLogicJwtForTokenStyle extends StpLogic {
|
||||
|
||||
/**
|
||||
* 初始化StpLogic, 并指定账号类型
|
||||
* @param loginType 账号体系标识
|
||||
*/
|
||||
public StpLogicJwtForTokenStyle() {
|
||||
super(StpUtil.TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化StpLogic, 并指定账号类型
|
||||
* @param loginType 账号体系标识
|
||||
*/
|
||||
public StpLogicJwtForTokenStyle(String loginType) {
|
||||
super(loginType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取jwt秘钥
|
||||
* @return /
|
||||
*/
|
||||
public String jwtSecretKey() {
|
||||
return getConfig().getJwtSecretKey();
|
||||
}
|
||||
|
||||
// ------ 重写方法
|
||||
|
||||
/**
|
||||
* 创建一个TokenValue
|
||||
* @param loginId loginId
|
||||
* @return 生成的tokenValue
|
||||
*/
|
||||
@Override
|
||||
public String createTokenValue(Object loginId) {
|
||||
return SaJwtUtil.createToken(loginId, jwtSecretKey());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user