mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-04-05 17:37:53 +08:00
refactor: 优化 Token-Session 获取算法,减少缓存读取次数
This commit is contained in:
parent
f2e9f7c222
commit
bb5ceb1dc0
@ -128,6 +128,9 @@ public interface SaErrorCode {
|
|||||||
/** 获取 Token-Session 时提供的 token 为空 */
|
/** 获取 Token-Session 时提供的 token 为空 */
|
||||||
int CODE_11073 = 11073;
|
int CODE_11073 = 11073;
|
||||||
|
|
||||||
|
/** 获取 Token-Session 时提供的 token 为无效 token */
|
||||||
|
int CODE_11074 = 11074;
|
||||||
|
|
||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
|
@ -1094,25 +1094,11 @@ public class StpLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 7、token 活跃频率检查
|
// 7、token 活跃频率检查
|
||||||
if(isOpenCheckActiveTimeout()) {
|
checkActiveTimeoutByConfig(tokenValue);
|
||||||
// storage.get(key, () -> {}) 可以避免一次请求多次校验,造成不必要的性能消耗
|
|
||||||
SaHolder.getStorage().get(SaTokenConsts.TOKEN_ACTIVE_TIMEOUT_CHECKED_KEY, () -> {
|
|
||||||
|
|
||||||
// 7.1、检查此 token 的最后活跃时间是否已经超过了 active-timeout 的限制,如果是则代表其已被冻结,需要抛出:token 已被冻结
|
// ------ 至此,loginId 已经是一个合法的值,代表当前会话是一个正常的登录状态了
|
||||||
checkActiveTimeout(tokenValue);
|
|
||||||
|
|
||||||
// ------ 至此,loginId 已经是一个合法的值,代表当前会话是一个正常的登录状态了
|
// 8、返回 loginId
|
||||||
|
|
||||||
// 7.2、如果配置了自动续签功能, 则: 更新这个 token 的最后活跃时间 (注意此处的续签是在续 active-timeout,而非 timeout)
|
|
||||||
if(SaStrategy.instance.autoRenew.apply(this)) {
|
|
||||||
updateLastActiveToNow(tokenValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 9、返回 loginId
|
|
||||||
return loginId;
|
return loginId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1277,16 +1263,26 @@ public class StpLogic {
|
|||||||
// ---- 其它操作
|
// ---- 其它操作
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断一个 loginId 是否是有效的
|
* 判断一个 loginId 是否是有效的 (判断标准:不为 null、空字符串,且不在异常标记项里面)
|
||||||
*
|
*
|
||||||
* @param loginId 账号id
|
* @param loginId 账号id
|
||||||
* @return /
|
* @return /
|
||||||
*/
|
*/
|
||||||
public boolean isValidLoginId(Object loginId) {
|
public boolean isValidLoginId(Object loginId) {
|
||||||
// 判断标准:不为 null、空字符串,且不在异常标记项里面
|
|
||||||
return SaFoxUtil.isNotEmpty(loginId) && !NotLoginException.ABNORMAL_LIST.contains(loginId.toString());
|
return SaFoxUtil.isNotEmpty(loginId) && !NotLoginException.ABNORMAL_LIST.contains(loginId.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断一个 token 是否是有效的 (判断标准:使用此 token 查询到的 loginId 不为 Empty )
|
||||||
|
*
|
||||||
|
* @param tokenValue /
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public boolean isValidToken(String tokenValue) {
|
||||||
|
Object loginId = getLoginIdByToken(tokenValue);
|
||||||
|
return SaFoxUtil.isNotEmpty(loginId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储 token - id 映射关系
|
* 存储 token - id 映射关系
|
||||||
*
|
*
|
||||||
@ -1454,10 +1450,32 @@ public class StpLogic {
|
|||||||
* @return session对象
|
* @return session对象
|
||||||
*/
|
*/
|
||||||
public SaSession getTokenSessionByToken(String tokenValue, boolean isCreate) {
|
public SaSession getTokenSessionByToken(String tokenValue, boolean isCreate) {
|
||||||
|
// 1、token 为空,不允许创建
|
||||||
if(SaFoxUtil.isEmpty(tokenValue)) {
|
if(SaFoxUtil.isEmpty(tokenValue)) {
|
||||||
throw new SaTokenException("Token-Session 获取失败:token 为空").setCode(SaErrorCode.CODE_11073);
|
throw new SaTokenException("Token-Session 获取失败:token 为空").setCode(SaErrorCode.CODE_11073);
|
||||||
}
|
}
|
||||||
return getSessionBySessionId(splicingKeyTokenSession(tokenValue), isCreate, null, session -> {
|
|
||||||
|
// 2、如果能查询到旧记录,则直接返回
|
||||||
|
String sessionId = splicingKeyTokenSession(tokenValue);
|
||||||
|
SaSession tokenSession = getSaTokenDao().getSession(sessionId);
|
||||||
|
if(tokenSession != null) {
|
||||||
|
return tokenSession;
|
||||||
|
}
|
||||||
|
// 以下是查不到的情况
|
||||||
|
|
||||||
|
// 3、指定了不需要创建,返回 null
|
||||||
|
if( ! isCreate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 以下是需要创建的情况
|
||||||
|
|
||||||
|
// 4、检查一下这个 token 是否为有效 token,无效 token 不允许创建
|
||||||
|
if(getConfigOrGlobal().getTokenSessionCheckLogin() && ! isValidToken(tokenValue)) {
|
||||||
|
throw new SaTokenException("Token-Session 获取失败,token 无效: " + tokenValue).setCode(SaErrorCode.CODE_11074);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5、创建 Token-Session 并返回
|
||||||
|
return getSessionBySessionId(sessionId, true, null, session -> {
|
||||||
// 这里是该 Token-Session 首次创建时才会被执行的方法:
|
// 这里是该 Token-Session 首次创建时才会被执行的方法:
|
||||||
// 设定这个 SaSession 的各种基础信息:类型、账号体系、Token 值
|
// 设定这个 SaSession 的各种基础信息:类型、账号体系、Token 值
|
||||||
session.setType(SaTokenConsts.SESSION_TYPE__TOKEN);
|
session.setType(SaTokenConsts.SESSION_TYPE__TOKEN);
|
||||||
@ -1483,20 +1501,8 @@ public class StpLogic {
|
|||||||
* @return Session对象
|
* @return Session对象
|
||||||
*/
|
*/
|
||||||
public SaSession getTokenSession(boolean isCreate) {
|
public SaSession getTokenSession(boolean isCreate) {
|
||||||
|
|
||||||
// 1、如果配置了:tokenSessionCheckLogin == true,则需要先校验当前是否登录,未登录情况下不允许拿到 Token-Session
|
|
||||||
if(getConfigOrGlobal().getTokenSessionCheckLogin()) {
|
|
||||||
checkLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2、如果前端根本没有提供 Token ,则直接返回 null
|
|
||||||
String tokenValue = getTokenValue();
|
String tokenValue = getTokenValue();
|
||||||
if(SaFoxUtil.isEmpty(tokenValue)) {
|
checkActiveTimeoutByConfig(tokenValue);
|
||||||
throw new SaTokenException("Token-Session 获取失败:token 为空").setCode(SaErrorCode.CODE_11073);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3、代码至此:tokenSessionCheckLogin 校验通过、且 Token 有值
|
|
||||||
// 现在根据前端提供的 Token 获取它对应的 Token-Session 对象(SaSession)
|
|
||||||
return getTokenSessionByToken(tokenValue, isCreate);
|
return getTokenSessionByToken(tokenValue, isCreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1682,6 +1688,29 @@ public class StpLogic {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据全局配置决定是否校验指定 token 的活跃度
|
||||||
|
*
|
||||||
|
* @param tokenValue 指定 token
|
||||||
|
*/
|
||||||
|
public void checkActiveTimeoutByConfig(String tokenValue) {
|
||||||
|
if(isOpenCheckActiveTimeout()) {
|
||||||
|
// storage.get(key, () -> {}) 可以避免一次请求多次校验,造成不必要的性能消耗
|
||||||
|
SaHolder.getStorage().get(SaTokenConsts.TOKEN_ACTIVE_TIMEOUT_CHECKED_KEY, () -> {
|
||||||
|
|
||||||
|
// 1、检查此 token 的最后活跃时间是否已经超过了 active-timeout 的限制,如果是则代表其已被冻结,需要抛出:token 已被冻结
|
||||||
|
checkActiveTimeout(tokenValue);
|
||||||
|
|
||||||
|
// 2、如果配置了自动续签功能, 则: 更新这个 token 的最后活跃时间 (注意此处的续签是在续 active-timeout,而非 timeout)
|
||||||
|
if(SaStrategy.instance.autoRenew.apply(this)) {
|
||||||
|
updateLastActiveToNow(tokenValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查指定 token 是否已被冻结,如果是则抛出异常
|
* 检查指定 token 是否已被冻结,如果是则抛出异常
|
||||||
*
|
*
|
||||||
|
@ -162,7 +162,7 @@ public final class SaStrategy {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否自动续期
|
* 是否自动续期 active-timeout
|
||||||
*/
|
*/
|
||||||
public SaAutoRenewFunction autoRenew = (stpLogic) -> {
|
public SaAutoRenewFunction autoRenew = (stpLogic) -> {
|
||||||
return stpLogic.getConfigOrGlobal().getAutoRenew();
|
return stpLogic.getConfigOrGlobal().getAutoRenew();
|
||||||
|
@ -48,7 +48,7 @@ sa-token.active-timeout=-1
|
|||||||
|
|
||||||
|
|
||||||
### 关于active-timeout的续签
|
### 关于active-timeout的续签
|
||||||
如果`active-timeout`配置了大于零的值,Sa-Token 会在登录时开始计时,在每次直接或间接调用`getLoginId()`时进行一次冻结检查与续签操作。
|
如果`active-timeout`配置了大于零的值,Sa-Token 会在登录时开始计时,在每次直接或间接调用`getLoginId()`、`getTokenSession()`时进行一次冻结检查与续签操作。
|
||||||
此时会有两种情况:
|
此时会有两种情况:
|
||||||
1. 一种是会话无操作时间太长,Token已经被冻结,此时框架会抛出`NotLoginException`异常(场景值=-3),
|
1. 一种是会话无操作时间太长,Token已经被冻结,此时框架会抛出`NotLoginException`异常(场景值=-3),
|
||||||
2. 另一种则是会话在`active-timeout`有效期内通过检查,此时Token可以成功续签
|
2. 另一种则是会话在`active-timeout`有效期内通过检查,此时Token可以成功续签
|
||||||
@ -85,8 +85,8 @@ StpUtil.stpLogic.updateLastActiveToNow(tokenValue);
|
|||||||
两者的认证逻辑彼此独立,互不干扰,可以同时使用。
|
两者的认证逻辑彼此独立,互不干扰,可以同时使用。
|
||||||
|
|
||||||
|
|
||||||
### StpUtil 类中哪些公开方法支持自动续签 active-timeout?
|
### StpUtil 类中哪些方法支持自动续签 active-timeout?
|
||||||
> 直接或间接获取了当前用户id的方法 (间接调用过 StpLogic.getLoginId() 方法)
|
> 直接或间接调用过 `getLoginId()`、`getTokenSession()` 的方法
|
||||||
|
|
||||||
| 包括但不限于这些: |
|
| 包括但不限于这些: |
|
||||||
|---|
|
|---|
|
||||||
|
Loading…
Reference in New Issue
Block a user