1
0
mirror of synced 2026-05-22 14:43:15 +00:00

feat: 新增 SaLogoutParameter,用于控制注销会话时的各种细节 & 优化注销会话相关 API & SaLoginParameter 新增 replacedMode、overflowLogoutMode & SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE 默认值改为 DEF

This commit is contained in:
click33
2025-03-13 23:58:18 +08:00
parent c7f27e393e
commit 79016e5ffe
31 changed files with 969 additions and 303 deletions
@@ -22,7 +22,7 @@ import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.error.SaErrorCode; import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
/** /**
@@ -17,7 +17,7 @@ package cn.dev33.satoken.listener;
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface; import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
/** /**
@@ -17,7 +17,7 @@ package cn.dev33.satoken.listener;
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface; import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
@@ -15,7 +15,7 @@
*/ */
package cn.dev33.satoken.listener; package cn.dev33.satoken.listener;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
/** /**
* Sa-Token 侦听器,默认空实现 * Sa-Token 侦听器,默认空实现
@@ -88,6 +88,11 @@ public class SaSession implements SaSetValueInterface, Serializable {
*/ */
private String token; private String token;
/**
* 当前账号历史总计登录设备数量 (当此 SaSession 属于 Account-Session 时,此值有效)
*/
private int historyTerminalCount;
/** /**
* 此 SaSession 的创建时间(13位时间戳) * 此 SaSession 的创建时间(13位时间戳)
*/ */
@@ -330,6 +335,8 @@ public class SaSession implements SaSetValueInterface, Serializable {
terminalList.remove(oldTerminal); terminalList.remove(oldTerminal);
} }
// 然后添加新的 // 然后添加新的
this.historyTerminalCount++;
terminalInfo.setIndex(this.historyTerminalCount);
terminalList.add(terminalInfo); terminalList.add(terminalInfo);
update(); update();
} }
@@ -347,20 +354,24 @@ public class SaSession implements SaSetValueInterface, Serializable {
} }
/** /**
* 获取最大的终端索引值,如无返0 * 获取 当前账号历史总计登录设备数量 (当此 SaSession 属于 Account-Session 时,此值有效)
*
* @return / * @return /
*/ */
public int maxTerminalIndex() { public int getHistoryTerminalCount() {
int max = 0; return this.historyTerminalCount;
for (SaTerminalInfo terminal : terminalListCopy()) {
int index = terminal.getIndex();
if (index > max) {
max = index;
}
}
return max;
} }
/**
* 设置 当前账号历史总计登录设备数量 (当此 SaSession 属于 Account-Session 时,此值有效)
*
* @param historyTerminalCount /
*/
public void setHistoryTerminalCount(int historyTerminalCount) {
this.historyTerminalCount = historyTerminalCount;
}
/** /**
* 判断指定设备 id 是否为可信任设备 * 判断指定设备 id 是否为可信任设备
* @param deviceId / * @param deviceId /
@@ -16,6 +16,7 @@
package cn.dev33.satoken.stp; package cn.dev33.satoken.stp;
import cn.dev33.satoken.SaManager; import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import java.util.Map; import java.util.Map;
@@ -15,6 +15,8 @@
*/ */
package cn.dev33.satoken.stp; package cn.dev33.satoken.stp;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
/** /**
* <h2> 请更改为 SaLoginParameter </h2> * <h2> 请更改为 SaLoginParameter </h2>
* 在调用 `StpUtil.login()` 时的 配置参数 Model,决定登录的一些细节行为 <br> * 在调用 `StpUtil.login()` 时的 配置参数 Model,决定登录的一些细节行为 <br>
@@ -31,6 +31,11 @@ import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.model.wrapperInfo.SaDisableWrapperInfo; import cn.dev33.satoken.model.wrapperInfo.SaDisableWrapperInfo;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.SaTerminalInfo; import cn.dev33.satoken.session.SaTerminalInfo;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import cn.dev33.satoken.stp.parameter.enums.SaLogoutMode;
import cn.dev33.satoken.stp.parameter.enums.SaLogoutRange;
import cn.dev33.satoken.stp.parameter.enums.SaReplacedMode;
import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaTokenConsts; import cn.dev33.satoken.util.SaTokenConsts;
@@ -473,7 +478,6 @@ public class StpLogic {
// 4、在 Account-Session 上记录本次登录的终端信息 // 4、在 Account-Session 上记录本次登录的终端信息
SaTerminalInfo terminalInfo = new SaTerminalInfo() SaTerminalInfo terminalInfo = new SaTerminalInfo()
.setIndex(session.maxTerminalIndex() + 1)
.setDeviceType(loginParameter.getDeviceType()) .setDeviceType(loginParameter.getDeviceType())
.setDeviceId(loginParameter.getDeviceId()) .setDeviceId(loginParameter.getDeviceId())
.setTokenValue(tokenValue) .setTokenValue(tokenValue)
@@ -500,7 +504,7 @@ public class StpLogic {
// 9、检查此账号会话数量是否超出最大值,如果超过,则按照登录时间顺序,把最开始登录的给注销掉 // 9、检查此账号会话数量是否超出最大值,如果超过,则按照登录时间顺序,把最开始登录的给注销掉
if(loginParameter.getMaxLoginCount() != -1) { if(loginParameter.getMaxLoginCount() != -1) {
logoutByMaxLoginCount(id, session, null, loginParameter.getMaxLoginCount()); logoutByMaxLoginCount(id, session, null, loginParameter.getMaxLoginCount(), loginParameter.getOverflowLogoutMode());
} }
// 10、一切处理完毕,返回会话凭证 token // 10、一切处理完毕,返回会话凭证 token
@@ -519,8 +523,12 @@ public class StpLogic {
// 1、获取全局配置的 isConcurrent 参数 // 1、获取全局配置的 isConcurrent 参数
// 如果配置为:不允许一个账号多地同时登录,则需要先将这个账号的历史登录会话标记为:被顶下线 // 如果配置为:不允许一个账号多地同时登录,则需要先将这个账号的历史登录会话标记为:被顶下线
if( ! loginParameter.getIsConcurrent()) { if( ! loginParameter.getIsConcurrent()) {
// TODO 此处应该加一个配置决定是只顶掉当前设备类型,还是所有类型 if(loginParameter.getReplacedMode() == SaReplacedMode.CURR_DEVICE_TYPE) {
replaced(id, loginParameter.getDeviceType()); replaced(id, loginParameter.getDeviceTypeOrDefault());
}
if(loginParameter.getReplacedMode() == SaReplacedMode.ALL_DEVICE_TYPE) {
replaced(id, createSaLogoutParameter());
}
} }
// 2、如果调用者预定了要生成的 token,则直接返回这个预定的值,框架无需再操心了 // 2、如果调用者预定了要生成的 token,则直接返回这个预定的值,框架无需再操心了
@@ -612,12 +620,19 @@ public class StpLogic {
return tokenValue; return tokenValue;
} }
// --- 注销 // --- 注销 (根据 token)
/** /**
* 在当前客户端会话注销 * 在当前客户端会话注销
*/ */
public void logout() { public void logout() {
logout(createSaLogoutParameter());
}
/**
* 在当前客户端会话注销,根据注销参数
*/
public void logout(SaLogoutParameter logoutParameter) {
// 1、如果本次请求连 Token 都没有提交,那么它本身也不属于登录状态,此时无需执行任何操作 // 1、如果本次请求连 Token 都没有提交,那么它本身也不属于登录状态,此时无需执行任何操作
String tokenValue = getTokenValue(); String tokenValue = getTokenValue();
if(SaFoxUtil.isEmpty(tokenValue)) { if(SaFoxUtil.isEmpty(tokenValue)) {
@@ -649,67 +664,338 @@ public class StpLogic {
storage.delete(SaTokenConsts.TOKEN_ACTIVE_TIMEOUT_CHECKED_KEY); storage.delete(SaTokenConsts.TOKEN_ACTIVE_TIMEOUT_CHECKED_KEY);
// 5、清除这个 token 的其它相关信息 // 5、清除这个 token 的其它相关信息
logoutByTokenValue(tokenValue); if(logoutParameter.getRange() == SaLogoutRange.TOKEN) {
logoutByTokenValue(tokenValue, logoutParameter);
} else {
Object loginId = getLoginIdByTokenNotThinkFreeze(tokenValue);
if(loginId != null) {
if(!logoutParameter.getIsKeepFreezeOps() && isFreeze(tokenValue)) {
return;
}
logout(loginId, logoutParameter);
}
}
} }
/** /**
* 会话注销,根据账号id * 注销下线,根据指定 token
* *
* @param loginId 账号id * @param tokenValue 指定 token
*/
public void logoutByTokenValue(String tokenValue) {
logoutByTokenValue(tokenValue, createSaLogoutParameter());
}
/**
* 注销下线,根据指定 token、注销参数
*
* @param tokenValue 指定 token
* @param logoutParameter /
*/
public void logoutByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
_logoutByTokenValue(tokenValue, logoutParameter.setMode(SaLogoutMode.LOGOUT));
}
/**
* 踢人下线,根据指定 token
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param tokenValue 指定 token
*/
public void kickoutByTokenValue(String tokenValue) {
kickoutByTokenValue(tokenValue, createSaLogoutParameter());
}
/**
* 踢人下线,根据指定 token、注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param tokenValue 指定 token
* @param logoutParameter 注销参数
*/
public void kickoutByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
_logoutByTokenValue(tokenValue, logoutParameter.setMode(SaLogoutMode.KICKOUT));
}
/**
* 顶人下线,根据指定 token
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param tokenValue 指定 token
*/
public void replacedByTokenValue(String tokenValue) {
replacedByTokenValue(tokenValue, createSaLogoutParameter());
}
/**
* 顶人下线,根据指定 token、注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param tokenValue 指定 token
* @param logoutParameter /
*/
public void replacedByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
_logoutByTokenValue(tokenValue, logoutParameter.setMode(SaLogoutMode.REPLACED));
}
/**
* [work] 注销下线,根据指定 token 、注销参数
*
* @param tokenValue 指定 token
* @param logoutParameter 注销参数
*/
public void _logoutByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
// 1、判断一下:如果此 token 映射的是一个无效 loginId,则此处立即返回,不需要再往下处理了
// 如果不提前截止,则后续的操作可能会写入意外数据
Object loginId = getLoginIdByTokenNotThinkFreeze(tokenValue);
if( SaFoxUtil.isEmpty(loginId) ) {
return;
}
if(!logoutParameter.getIsKeepFreezeOps() && isFreeze(tokenValue)) {
return;
}
// 2、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 3、清除 Token-Session
if( ! logoutParameter.getIsKeepTokenSession()) {
deleteTokenSession(tokenValue);
}
// 4、清理或更改 Token 映射
// 5、发布事件通知
// SaLogoutMode.LOGOUT:注销下线
if(logoutParameter.getMode() == SaLogoutMode.LOGOUT) {
deleteTokenToIdMapping(tokenValue);
SaTokenEventCenter.doLogout(loginType, loginId, tokenValue);
}
// SaLogoutMode.LOGOUT:踢人下线
if(logoutParameter.getMode() == SaLogoutMode.KICKOUT) {
updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT);
SaTokenEventCenter.doKickout(loginType, loginId, tokenValue);
}
// SaLogoutMode.REPLACED:顶人下线
if(logoutParameter.getMode() == SaLogoutMode.REPLACED) {
updateTokenToIdMapping(tokenValue, NotLoginException.BE_REPLACED);
SaTokenEventCenter.doReplaced(loginType, loginId, tokenValue);
}
// 6、清理这个账号的 Account-Session 上的 terminal 信息,并且尝试注销掉 Account-Session
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
session.removeTerminal(tokenValue);
session.logoutByTerminalCountToZero();
}
}
// --- 注销 (根据 loginId)
/**
* 会话注销,根据账号id
*
* @param loginId 账号id
*/ */
public void logout(Object loginId) { public void logout(Object loginId) {
logout(loginId, null); logout(loginId, createSaLogoutParameter());
} }
/** /**
* 会话注销,根据账号id 和 设备类型 * 会话注销,根据账号id 和 设备类型
* *
* @param loginId 账号id * @param loginId 账号id
* @param deviceType 设备类型 (填 null 代表注销该账号的所有设备类型) * @param deviceType 设备类型 (填 null 代表注销该账号的所有设备类型)
*/ */
public void logout(Object loginId, String deviceType) { public void logout(Object loginId, String deviceType) {
logout(loginId, createSaLogoutParameter().setDeviceType(deviceType));
}
/**
* 会话注销,根据账号id 和 注销参数
*
* @param loginId 账号id
* @param logoutParameter 注销参数
*/
public void logout(Object loginId, SaLogoutParameter logoutParameter) {
_logout(loginId, logoutParameter.setMode(SaLogoutMode.LOGOUT));
}
/**
* 踢人下线,根据账号id
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param loginId 账号id
*/
public void kickout(Object loginId) {
kickout(loginId, createSaLogoutParameter());
}
/**
* 踢人下线,根据账号id 和 设备类型
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param loginId 账号id
* @param deviceType 设备类型 (填 null 代表踢出该账号的所有设备类型)
*/
public void kickout(Object loginId, String deviceType) {
kickout(loginId, createSaLogoutParameter().setDeviceType(deviceType));
}
/**
* 踢人下线,根据账号id 和 注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param loginId 账号id
* @param logoutParameter 注销参数
*/
public void kickout(Object loginId, SaLogoutParameter logoutParameter) {
_logout(loginId, logoutParameter.setMode(SaLogoutMode.KICKOUT));
}
/**
* 顶人下线,根据账号id
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param loginId 账号id
*/
public void replaced(Object loginId) {
replaced(loginId, createSaLogoutParameter());
}
/**
* 顶人下线,根据账号id 和 设备类型
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param loginId 账号id
* @param deviceType 设备类型 (填 null 代表顶替该账号的所有设备类型)
*/
public void replaced(Object loginId, String deviceType) {
replaced(loginId, createSaLogoutParameter().setDeviceType(deviceType));
}
/**
* 顶人下线,根据账号id 和 注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param loginId 账号id
* @param logoutParameter 注销参数
*/
public void replaced(Object loginId, SaLogoutParameter logoutParameter) {
_logout(loginId, logoutParameter.setMode(SaLogoutMode.REPLACED));
}
/**
* [work] 会话注销,根据账号id 和 注销参数
*
* @param loginId 账号id
* @param logoutParameter 注销参数
*/
public void _logout(Object loginId, SaLogoutParameter logoutParameter) {
// 1、获取此账号的 Account-Session,上面记录了此账号的所有登录客户端数据 // 1、获取此账号的 Account-Session,上面记录了此账号的所有登录客户端数据
SaSession session = getSessionByLoginId(loginId, false); SaSession session = getSessionByLoginId(loginId, false);
if(session != null) { if(session != null) {
// 2、遍历此账号所有从这个 deviceType 设备类型上登录的客户端,清除相关数据 // 2、遍历此 SaTerminalInfo 客户端列表,清除相关数据
for (SaTerminalInfo terminal: session.getTerminalListByDeviceType(deviceType)) { List<SaTerminalInfo> terminalList = session.getTerminalListByDeviceType(logoutParameter.getDeviceType());
for (SaTerminalInfo terminal: terminalList) {
// 2.1、获取此客户端的 token 值 _removeTerminal(session, terminal, logoutParameter);
String tokenValue = terminal.getTokenValue();
// 2.2、从 Account-Session 上清除此设备信息
session.removeTerminal(tokenValue);
// 2.3、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 2.4、清除 token -> id 的映射关系
deleteTokenToIdMapping(tokenValue);
// 2.5、清除这个 token 的 Token-Session 对象
deleteTokenSession(tokenValue);
// 2.6、$$ 发布事件:xx 账号的 xx 客户端注销了
SaTokenEventCenter.doLogout(loginType, loginId, tokenValue);
} }
// 3、如果代码走到这里的时候,此账号已经没有客户端在登录了,则直接注销掉这个 Account-Session // 3、如果代码走到这里的时候,此账号已经没有客户端在登录了,则直接注销掉这个 Account-Session
session.logoutByTerminalCountToZero(); if(logoutParameter.getMode() == SaLogoutMode.REPLACED) {
// 因为调用顶替下线时,一般都是在新客户端正在登录,所以此种情况不需要清除该账号的 Account-Session
// 如果清除了 Account-Session,将可能导致 Account-Session 被注销后又立刻创建出来,造成不必要的性能浪费
} else {
session.logoutByTerminalCountToZero();
}
} }
} }
// --- 注销 (会话管理辅助方法)
/**
* 在 Account-Session 上移除 Terminal 信息 (注销下线方式)
* @param session /
* @param terminal /
*/
public void removeTerminalByLogout(SaSession session, SaTerminalInfo terminal) {
_removeTerminal(session, terminal, createSaLogoutParameter().setMode(SaLogoutMode.LOGOUT));
}
/**
* 在 Account-Session 上移除 Terminal 信息 (踢人下线方式)
* @param session /
* @param terminal /
*/
public void removeTerminalByKickout(SaSession session, SaTerminalInfo terminal) {
_removeTerminal(session, terminal, createSaLogoutParameter().setMode(SaLogoutMode.KICKOUT));
}
/**
* 在 Account-Session 上移除 Terminal 信息 (顶人下线方式)
* @param session /
* @param terminal /
*/
public void removeTerminalByReplaced(SaSession session, SaTerminalInfo terminal) {
_removeTerminal(session, terminal, createSaLogoutParameter().setMode(SaLogoutMode.REPLACED));
}
/**
* 在 Account-Session 上移除 Terminal 信息 (内部方法,仅为减少重复代码,外部调用意义不大)
* @param session Account-Session
* @param terminal 设备信息
* @param logoutParameter 注销参数
*/
public void _removeTerminal(SaSession session, SaTerminalInfo terminal, SaLogoutParameter logoutParameter) {
Object loginId = session.getLoginId();
String tokenValue = terminal.getTokenValue();
// 1、从 Account-Session 上清除此设备信息
session.removeTerminal(tokenValue);
// 2、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 3、清除这个 token 的 Token-Session 对象
if( ! logoutParameter.getIsKeepTokenSession()) {
deleteTokenSession(tokenValue);
}
// 4、清理或更改 Token 映射
// 5、发布事件通知
// SaLogoutMode.LOGOUT:注销下线
if(logoutParameter.getMode() == SaLogoutMode.LOGOUT) {
deleteTokenToIdMapping(tokenValue);
SaTokenEventCenter.doLogout(loginType, loginId, tokenValue);
}
// SaLogoutMode.LOGOUT:踢人下线
if(logoutParameter.getMode() == SaLogoutMode.KICKOUT) {
updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT);
SaTokenEventCenter.doKickout(loginType, loginId, tokenValue);
}
// SaLogoutMode.REPLACED:顶人下线
if(logoutParameter.getMode() == SaLogoutMode.REPLACED) {
updateTokenToIdMapping(tokenValue, NotLoginException.BE_REPLACED);
SaTokenEventCenter.doReplaced(loginType, loginId, tokenValue);
}
}
/** /**
* 如果指定账号 id、设备类型的登录客户端已经超过了指定数量,则按照登录时间顺序,把最开始登录的给注销掉 * 如果指定账号 id、设备类型的登录客户端已经超过了指定数量,则按照登录时间顺序,把最开始登录的给注销掉
* *
* @param loginId 账号id * @param loginId 账号id
* @param session 此账号的 Account-Session 对象,可填写 null,框架将自动获取 * @param session 此账号的 Account-Session 对象,可填写 null,框架将自动获取
* @param deviceType 设备类型(填 null 代表注销此账号所有设备类型的登录) * @param deviceType 设备类型(填 null 代表注销此账号所有设备类型的登录)
* @param maxLoginCount 最大登录数量,超过此数量的将被注销 * @param maxLoginCount 最大登录数量,超过此数量的将被注销
* @param logoutMode 超出的客户端将以何种方式被注销
*/ */
public void logoutByMaxLoginCount(Object loginId, SaSession session, String deviceType, int maxLoginCount) { public void logoutByMaxLoginCount(Object loginId, SaSession session, String deviceType, int maxLoginCount, SaLogoutMode logoutMode) {
// 1、如果调用者提供的 Account-Session 对象为空,则我们先手动获取一下 // 1、如果调用者提供的 Account-Session 对象为空,则我们先手动获取一下
if(session == null) { if(session == null) {
@@ -724,196 +1010,14 @@ public class StpLogic {
// 3、按照登录时间倒叙,超过 maxLoginCount 数量的,全部注销掉 // 3、按照登录时间倒叙,超过 maxLoginCount 数量的,全部注销掉
for (int i = 0; i < list.size() - maxLoginCount; i++) { for (int i = 0; i < list.size() - maxLoginCount; i++) {
_removeTerminal(session, list.get(i), createSaLogoutParameter().setMode(logoutMode));
// 3.1、获取此客户端的 token 值
String tokenValue = list.get(i).getTokenValue();
// 3.2、从 Account-Session 上清除 terminal 信息
session.removeTerminal(tokenValue);
// 3.3、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 3.4、清除 token -> id 的映射关系
deleteTokenToIdMapping(tokenValue);
// 3.5、清除这个 token 的 Token-Session 对象
deleteTokenSession(tokenValue);
// 3.6、$$ 发布事件:xx 账号的 xx 客户端注销了
SaTokenEventCenter.doLogout(loginType, loginId, tokenValue);
} }
// 4、如果代码走到这里的时候,此账号已经没有客户端在登录了,则直接注销掉这个 Account-Session // 4、如果代码走到这里的时候,此账号已经没有客户端在登录了,则直接注销掉这个 Account-Session
session.logoutByTerminalCountToZero(); session.logoutByTerminalCountToZero();
} }
/**
* 会话注销,根据指定 Token
*
* @param tokenValue 指定 token
*/
public void logoutByTokenValue(String tokenValue) {
// 1、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 2、清除这个 token 的 Token-Session 对象
deleteTokenSession(tokenValue);
// 3、清除 token -> id 的映射关系
String loginId = getLoginIdNotHandle(tokenValue);
if(loginId != null) {
deleteTokenToIdMapping(tokenValue);
}
// 4、判断一下:如果此 token 映射的是一个无效 loginId,则此处立即返回,不需要再往下处理了
if( ! isValidLoginId(loginId) ) {
return;
}
// 5、$$ 发布事件:某某账号的某某 token 注销下线了
SaTokenEventCenter.doLogout(loginType, loginId, tokenValue);
// 6、清理这个账号的 Account-Session 上的 terminal 信息,并且尝试注销掉 Account-Session
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
session.removeTerminal(tokenValue);
session.logoutByTerminalCountToZero();
}
}
/**
* 踢人下线,根据账号id
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param loginId 账号id
*/
public void kickout(Object loginId) {
kickout(loginId, null);
}
/**
* 踢人下线,根据账号id 和 设备类型
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param loginId 账号id
* @param deviceType 设备类型 (填 null 代表踢出该账号的所有设备类型)
*/
public void kickout(Object loginId, String deviceType) {
// 1、获取此账号的 Account-Session,上面记录了此账号的所有登录客户端数据
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
// 2、遍历此账号所有从这个 deviceType 设备上登录的客户端,清除相关数据
for (SaTerminalInfo terminal: session.getTerminalListByDeviceType(deviceType)) {
// 2.1、获取此客户端的 token 值
String tokenValue = terminal.getTokenValue();
// 2.2、从 Account-Session 上清除 terminal 信息
session.removeTerminal(tokenValue);
// 2.3、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 2.4、将此 token 标记为:已被踢下线
updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT);
// 2.5、清除 Token-Session
deleteTokenSession(tokenValue);
// 2.6、$$ 发布事件:xx 账号的 xx 客户端被踢下线了
SaTokenEventCenter.doKickout(loginType, loginId, tokenValue);
}
// 3、如果代码走到这里的时候,此账号已经没有客户端在登录了,则直接注销掉这个 Account-Session
session.logoutByTerminalCountToZero();
}
}
/**
* 踢人下线,根据指定 token
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param tokenValue 指定 token
*/
public void kickoutByTokenValue(String tokenValue) {
// 1、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 2、清除 Token-Session
deleteTokenSession(tokenValue);
// 3、判断一下:如果此 token 映射的是一个无效 loginId,则此处立即返回,不需要再往下处理了
String loginId = getLoginIdNotHandle(tokenValue);
if( ! isValidLoginId(loginId) ) {
return;
}
// 4、将此 token 标记为:已被踢下线
updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT);
// 5、$$. 发布事件:某某 token 被踢下线了
SaTokenEventCenter.doKickout(loginType, loginId, tokenValue);
// 6、清理这个账号的 Account-Session 上的 terminal 信息,并且尝试注销掉 Account-Session
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
session.removeTerminal(tokenValue);
session.logoutByTerminalCountToZero();
}
}
/**
* 顶人下线,根据账号id 和 设备类型
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param loginId 账号id
* @param deviceType 设备类型 (填 null 代表顶替该账号的所有设备类型)
*/
public void replaced(Object loginId, String deviceType) {
// 1、获取此账号的 Account-Session,上面记录了此账号的所有登录客户端数据
SaSession session = getSessionByLoginId(loginId, false);
if(session != null) {
// 2、遍历此账号所有从这个 deviceType 设备上登录的客户端,清除相关数据
for (SaTerminalInfo ter: session.getTerminalListByDeviceType(deviceType)) {
// 2.1、获取此客户端的 token 值
String tokenValue = ter.getTokenValue();
// 2.2、从 Account-Session 上清除 terminal 信息
session.removeTerminal(tokenValue);
// 2.3、清除这个 token 的最后活跃时间记录
if(isOpenCheckActiveTimeout()) {
clearLastActive(tokenValue);
}
// 2.4、将此 token 标记为:已被顶下线
updateTokenToIdMapping(tokenValue, NotLoginException.BE_REPLACED);
// 2.5、清除 Token-Session 对象
deleteTokenSession(tokenValue);
// 2.6、$$ 发布事件:xx 账号的 xx 客户端注销了
SaTokenEventCenter.doReplaced(loginType, loginId, tokenValue);
}
// 3、因为调用顶替下线时,一般都是在新客户端正在登录,所以此处不需要清除该账号的 Account-Session
// 如果此处清除了 Account-Session,将可能导致 Account-Session 被注销后又立刻创建出来,造成不必要的性能浪费
// session.logoutByTerminalCountToZero();
}
}
// ---- 会话查询 // ---- 会话查询
/** /**
@@ -1092,28 +1196,49 @@ public class StpLogic {
} }
/** /**
* 获取指定 token 对应的账号id,如果未登录,则返回 null * 获取指定 token 对应的账号id,如果 token 无效或 token 处于被踢、被顶、被冻结等状态,则返回 null
* *
* @param tokenValue token * @param tokenValue token
* @return 账号id * @return 账号id
*/ */
public Object getLoginIdByToken(String tokenValue) { public Object getLoginIdByToken(String tokenValue) {
// 1、如果提供的 token 为空,则直接返回 null Object loginId = getLoginIdByTokenNotThinkFreeze(tokenValue);
if(SaFoxUtil.isEmpty(tokenValue)) {
return null;
}
// 2、查找此 token 对应的 loginId,如果找不到或找的到但属于无效值,则返回 null if( SaFoxUtil.isNotEmpty(loginId) ) {
String loginId = getLoginIdNotHandle(tokenValue); // 如果 token 已被冻结,也返回 null
if( ! isValidLoginId(loginId) ) { long activeTimeout = getTokenActiveTimeoutByToken(tokenValue);
return null; if(activeTimeout == SaTokenDao.NOT_VALUE_EXPIRE) {
} return null;
}
}
// 3、返回
return loginId; return loginId;
} }
/**
* 获取指定 token 对应的账号id,如果 token 无效或 token 处于被踢、被顶等状态 (不考虑被冻结),则返回 null
*
* @param tokenValue token
* @return 账号id
*/
public Object getLoginIdByTokenNotThinkFreeze(String tokenValue) {
// 1、如果提供的 token 为空,则直接返回 null
if(SaFoxUtil.isEmpty(tokenValue)) {
return null;
}
// 2、查找此 token 对应的 loginId,如果找不到或找的到但属于无效值,则返回 null
String loginId = getLoginIdNotHandle(tokenValue);
if( ! isValidLoginId(loginId) ) {
return null;
}
// 3、返回
return loginId;
}
/** /**
* 获取指定 token 对应的账号id (不做任何特殊处理) * 获取指定 token 对应的账号id (不做任何特殊处理)
* *
@@ -1530,24 +1655,36 @@ public class StpLogic {
protected void clearLastActive(String tokenValue) { protected void clearLastActive(String tokenValue) {
getSaTokenDao().delete(splicingKeyLastActiveTime(tokenValue)); getSaTokenDao().delete(splicingKeyLastActiveTime(tokenValue));
} }
/** /**
* 判断指定 token 是否已被冻结
*
* @param tokenValue 指定 token
*/
public boolean isFreeze(String tokenValue) {
// 1、获取这个 token 的剩余活跃有效期
long activeTimeout = getTokenActiveTimeoutByToken(tokenValue);
// 2、值为 -1 代表此 token 已经被设置永不冻结
if(activeTimeout == SaTokenDao.NEVER_EXPIRE) {
return false;
}
// 3、值为 -2 代表已被冻结
if(activeTimeout == SaTokenDao.NOT_VALUE_EXPIRE) {
return true;
}
return false;
}
/**
* 检查指定 token 是否已被冻结,如果是则抛出异常 * 检查指定 token 是否已被冻结,如果是则抛出异常
* *
* @param tokenValue 指定 token * @param tokenValue 指定 token
*/ */
public void checkActiveTimeout(String tokenValue) { public void checkActiveTimeout(String tokenValue) {
if (isFreeze(tokenValue)) {
// 1、获取这个 token 的剩余活跃有效期
long activeTimeout = getTokenActiveTimeoutByToken(tokenValue);
// 2、值为 -1 代表此 token 已经被设置永不冻结,无须继续验证
if(activeTimeout == SaTokenDao.NEVER_EXPIRE) {
return;
}
// 3、值为 -2 代表已被冻结,此时需要抛出异常
if(activeTimeout == SaTokenDao.NOT_VALUE_EXPIRE) {
throw NotLoginException.newInstance(loginType, TOKEN_FREEZE, TOKEN_FREEZE_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11016); throw NotLoginException.newInstance(loginType, TOKEN_FREEZE, TOKEN_FREEZE_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11016);
} }
} }
@@ -2929,6 +3066,15 @@ public class StpLogic {
return new SaLoginParameter(getConfigOrGlobal()); return new SaLoginParameter(getConfigOrGlobal());
} }
/**
* 根据当前配置对象创建一个 SaLogoutParameter 对象
*
* @return /
*/
public SaLogoutParameter createSaLogoutParameter() {
return new SaLogoutParameter(getConfigOrGlobal());
}
// ------------------- 过期方法 ------------------- // ------------------- 过期方法 -------------------
@@ -20,6 +20,8 @@ import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.SaTerminalInfo; import cn.dev33.satoken.session.SaTerminalInfo;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
import java.util.List; import java.util.List;
@@ -235,7 +237,7 @@ public class StpUtil {
return stpLogic.getOrCreateLoginSession(id); return stpLogic.getOrCreateLoginSession(id);
} }
// --- 注销 // --- 注销 (根据 token)
/** /**
* 在当前客户端会话注销 * 在当前客户端会话注销
@@ -245,7 +247,77 @@ public class StpUtil {
} }
/** /**
* 会话注销,根据账号id * 在当前客户端会话注销,根据注销参数
*/
public static void logout(SaLogoutParameter logoutParameter) {
stpLogic.logout(logoutParameter);
}
/**
* 注销下线,根据指定 token
*
* @param tokenValue 指定 token
*/
public static void logoutByTokenValue(String tokenValue) {
stpLogic.logoutByTokenValue(tokenValue);
}
/**
* 注销下线,根据指定 token、注销参数
*
* @param tokenValue 指定 token
* @param logoutParameter /
*/
public static void logoutByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
stpLogic.logoutByTokenValue(tokenValue, logoutParameter);
}
/**
* 踢人下线,根据指定 token
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param tokenValue 指定 token
*/
public static void kickoutByTokenValue(String tokenValue) {
stpLogic.kickoutByTokenValue(tokenValue);
}
/**
* 踢人下线,根据指定 token、注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
*
* @param tokenValue 指定 token
* @param logoutParameter 注销参数
*/
public static void kickoutByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
stpLogic.kickoutByTokenValue(tokenValue, logoutParameter);
}
/**
* 顶人下线,根据指定 token
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param tokenValue 指定 token
*/
public static void replacedByTokenValue(String tokenValue) {
stpLogic.replacedByTokenValue(tokenValue);
}
/**
* 顶人下线,根据指定 token、注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param tokenValue 指定 token
* @param logoutParameter /
*/
public static void replacedByTokenValue(String tokenValue, SaLogoutParameter logoutParameter) {
stpLogic.replacedByTokenValue(tokenValue, logoutParameter);
}
// --- 注销 (根据 loginId)
/**
* 会话注销,根据账号id
* *
* @param loginId 账号id * @param loginId 账号id
*/ */
@@ -256,7 +328,7 @@ public class StpUtil {
/** /**
* 会话注销,根据账号id 和 设备类型 * 会话注销,根据账号id 和 设备类型
* *
* @param loginId 账号id * @param loginId 账号id
* @param deviceType 设备类型 (填 null 代表注销该账号的所有设备类型) * @param deviceType 设备类型 (填 null 代表注销该账号的所有设备类型)
*/ */
public static void logout(Object loginId, String deviceType) { public static void logout(Object loginId, String deviceType) {
@@ -264,19 +336,20 @@ public class StpUtil {
} }
/** /**
* 会话注销,根据指定 Token * 会话注销,根据账号id 和 注销参数
* *
* @param tokenValue 指定 token * @param loginId 账号id
* @param logoutParameter 注销参数
*/ */
public static void logoutByTokenValue(String tokenValue) { public static void logout(Object loginId, SaLogoutParameter logoutParameter) {
stpLogic.logoutByTokenValue(tokenValue); stpLogic.logout(loginId, logoutParameter);
} }
/** /**
* 踢人下线,根据账号id * 踢人下线,根据账号id
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p> * <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
* *
* @param loginId 账号id * @param loginId 账号id
*/ */
public static void kickout(Object loginId) { public static void kickout(Object loginId) {
stpLogic.kickout(loginId); stpLogic.kickout(loginId);
@@ -294,13 +367,24 @@ public class StpUtil {
} }
/** /**
* 踢人下线,根据指定 token * 踢人下线,根据账号id 和 注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p> * <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 </p>
* *
* @param tokenValue 指定 token * @param loginId 账号id
* @param logoutParameter 注销参数
*/ */
public static void kickoutByTokenValue(String tokenValue) { public static void kickout(Object loginId, SaLogoutParameter logoutParameter) {
stpLogic.kickoutByTokenValue(tokenValue); stpLogic.kickout(loginId, logoutParameter);
}
/**
* 顶人下线,根据账号id
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param loginId 账号id
*/
public static void replaced(Object loginId) {
stpLogic.replaced(loginId);
} }
/** /**
@@ -314,6 +398,47 @@ public class StpUtil {
stpLogic.replaced(loginId, deviceType); stpLogic.replaced(loginId, deviceType);
} }
/**
* 顶人下线,根据账号id 和 注销参数
* <p> 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4 </p>
*
* @param loginId 账号id
* @param logoutParameter 注销参数
*/
public static void replaced(Object loginId, SaLogoutParameter logoutParameter) {
stpLogic.replaced(loginId, logoutParameter);
}
// --- 注销 (会话管理辅助方法)
/**
* 在 Account-Session 上移除 Terminal 信息 (注销下线方式)
* @param session /
* @param terminal /
*/
public static void removeTerminalByLogout(SaSession session, SaTerminalInfo terminal) {
stpLogic.removeTerminalByLogout(session, terminal);
}
/**
* 在 Account-Session 上移除 Terminal 信息 (踢人下线方式)
* @param session /
* @param terminal /
*/
public static void removeTerminalByKickout(SaSession session, SaTerminalInfo terminal) {
stpLogic.removeTerminalByKickout(session, terminal);
}
/**
* 在 Account-Session 上移除 Terminal 信息 (顶人下线方式)
* @param session /
* @param terminal /
*/
public static void removeTerminalByReplaced(SaSession session, SaTerminalInfo terminal) {
stpLogic.removeTerminalByReplaced(session, terminal);
}
// 会话查询 // 会话查询
/** /**
@@ -398,7 +523,7 @@ public class StpUtil {
} }
/** /**
* 获取指定 token 对应的账号id,如果未登录,则返回 null * 获取指定 token 对应的账号id,如果 token 无效或 token 处于被踢、被顶、被冻结等状态,则返回 null
* *
* @param tokenValue token * @param tokenValue token
* @return 账号id * @return 账号id
@@ -407,6 +532,16 @@ public class StpUtil {
return stpLogic.getLoginIdByToken(tokenValue); return stpLogic.getLoginIdByToken(tokenValue);
} }
/**
* 获取指定 token 对应的账号id,如果 token 无效或 token 处于被踢、被顶等状态 (不考虑被冻结),则返回 null
*
* @param tokenValue token
* @return 账号id
*/
public Object getLoginIdByTokenNotThinkFreeze(String tokenValue) {
return stpLogic.getLoginIdByTokenNotThinkFreeze(tokenValue);
}
/** /**
* 获取当前 Token 的扩展信息(此函数只在jwt模式下生效) * 获取当前 Token 的扩展信息(此函数只在jwt模式下生效)
* *
@@ -13,18 +13,20 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package cn.dev33.satoken.stp; package cn.dev33.satoken.stp.parameter;
import cn.dev33.satoken.SaManager; import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.stp.parameter.enums.SaLogoutMode;
import cn.dev33.satoken.stp.parameter.enums.SaReplacedMode;
import cn.dev33.satoken.util.SaTokenConsts; import cn.dev33.satoken.util.SaTokenConsts;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
* 在调用 `StpUtil.login()` 时的 配置参数 Model决定登录的一些细节行为 <br> * 在调用 `StpUtil.login()` 时的 配置参数对象决定登录的一些细节行为 <br>
* *
* <pre> * <pre>
* // 例如在登录时指定 token 有效期为七天代码如下 * // 例如在登录时指定 token 有效期为七天代码如下
@@ -48,6 +50,16 @@ public class SaLoginParameter {
*/ */
private String deviceId; private String deviceId;
/**
* 顶人下线的范围
*/
private SaReplacedMode replacedMode = SaReplacedMode.CURR_DEVICE_TYPE;
/**
* 溢出 maxLoginCount 的客户端将以何种方式注销下线
*/
private SaLogoutMode overflowLogoutMode = SaLogoutMode.LOGOUT;
/** /**
* 扩展信息只在 jwt 模式下生效 * 扩展信息只在 jwt 模式下生效
*/ */
@@ -123,7 +135,7 @@ public class SaLoginParameter {
* @return 对象自身 * @return 对象自身
*/ */
public SaLoginParameter setDefaultValues(SaTokenConfig config) { public SaLoginParameter setDefaultValues(SaTokenConfig config) {
this.deviceType = SaTokenConsts.DEFAULT_LOGIN_DEVICE; this.deviceType = SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE;
this.timeout = config.getTimeout(); this.timeout = config.getTimeout();
this.isConcurrent = config.getIsConcurrent(); this.isConcurrent = config.getIsConcurrent();
this.isShare = config.getIsShare(); this.isShare = config.getIsShare();
@@ -220,9 +232,9 @@ public class SaLoginParameter {
/** /**
* @return 获取device参数如果为null则返回默认值 * @return 获取device参数如果为null则返回默认值
*/ */
public String getDeviceOrDefault() { public String getDeviceTypeOrDefault() {
if(deviceType == null) { if(deviceType == null) {
return SaTokenConsts.DEFAULT_LOGIN_DEVICE; return SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE;
} }
return deviceType; return deviceType;
} }
@@ -274,6 +286,45 @@ public class SaLoginParameter {
return this; return this;
} }
/**
* 获取 顶人下线的范围
*
* @return replacedMode 顶人下线的范围
*/
public SaReplacedMode getReplacedMode() {
return this.replacedMode;
}
/**
* 设置 顶人下线的范围
*
* @param replacedMode /
* @return 对象自身
*/
public SaLoginParameter setReplacedMode(SaReplacedMode replacedMode) {
this.replacedMode = replacedMode;
return this;
}
/**
* 获取 溢出 maxLoginCount 的客户端将以何种方式注销下线
*
* @return overflowLogoutMode /
*/
public SaLogoutMode getOverflowLogoutMode() {
return this.overflowLogoutMode;
}
/**
* 设置 溢出 maxLoginCount 的客户端将以何种方式注销下线
*
* @param overflowLogoutMode /
* @return 对象自身
*/
public SaLoginParameter setOverflowLogoutMode(SaLogoutMode overflowLogoutMode) {
this.overflowLogoutMode = overflowLogoutMode;
return this;
}
/** /**
* @return 是否为持久Cookie临时Cookie在浏览器关闭时会自动删除持久Cookie在重新打开后依然存在 * @return 是否为持久Cookie临时Cookie在浏览器关闭时会自动删除持久Cookie在重新打开后依然存在
*/ */
@@ -462,6 +513,8 @@ public class SaLoginParameter {
return "SaLoginParameter [" return "SaLoginParameter ["
+ "deviceType=" + deviceType + "deviceType=" + deviceType
+ ", deviceId=" + deviceId + ", deviceId=" + deviceId
+ ", replacedMode=" + replacedMode
+ ", overflowLogoutMode=" + overflowLogoutMode
+ ", isLastingCookie=" + isLastingCookie + ", isLastingCookie=" + isLastingCookie
+ ", timeout=" + timeout + ", timeout=" + timeout
+ ", activeTimeout=" + activeTimeout + ", activeTimeout=" + activeTimeout
@@ -0,0 +1,203 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.stp.parameter;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.parameter.enums.SaLogoutMode;
import cn.dev33.satoken.stp.parameter.enums.SaLogoutRange;
/**
* 在会话注销时的 配置参数对象,决定注销时的一些细节行为 <br>
*
* <pre>
* // 例如:
* StpUtil.logout(10001, new SaLogoutParameter());
* </pre>
*
* @author click33
* @since 1.41.0
*/
public class SaLogoutParameter {
/**
* 是否保留 Token-Session
*/
private Boolean isKeepTokenSession = false;
/**
* 如果 token 已被冻结,是否保留其操作权 (是否允许此 token 调用注销API)
*/
private Boolean isKeepFreezeOps = false;
/**
* 设备类型 (如果不指定,则默认注销所有客户端)
*/
private String deviceType;
/**
* 注销类型
*/
private SaLogoutMode mode = SaLogoutMode.LOGOUT;
/**
* 注销范围 (此参数只在调用 StpUtil.logout(new SaLogoutParameter()) 时有效)
*/
private SaLogoutRange range = SaLogoutRange.TOKEN;
// ------ 附加方法
public SaLogoutParameter() {
this(SaManager.getConfig());
}
public SaLogoutParameter(SaTokenConfig config) {
setDefaultValues(config);
}
/**
* 根据 SaTokenConfig 对象初始化默认值
*
* @param config 使用的配置对象
* @return 对象自身
*/
public SaLogoutParameter setDefaultValues(SaTokenConfig config) {
return this;
}
/**
* 静态方法获取一个 SaLoginParameter 对象
* @return SaLoginParameter 对象
*/
public static SaLogoutParameter create() {
return new SaLogoutParameter(SaManager.getConfig());
}
// ---------------- get set
/**
* @return 是否保留 Token-Session
*/
public Boolean getIsKeepTokenSession() {
return isKeepTokenSession;
}
/**
* @param isKeepTokenSession 是否保留 Token-Session
*
* @return 对象自身
*/
public SaLogoutParameter setIsKeepTokenSession(Boolean isKeepTokenSession) {
this.isKeepTokenSession = isKeepTokenSession;
return this;
}
/**
* 获取 如果 token 已被冻结,是否保留其操作权 (是否允许此 token 调用注销API)
*
* @return /
*/
public Boolean getIsKeepFreezeOps() {
return this.isKeepFreezeOps;
}
/**
* 设置 如果 token 已被冻结,是否保留其操作权 (是否允许此 token 调用注销API)
*
* @param isKeepFreezeOps /
* @return 对象自身
*/
public SaLogoutParameter setIsKeepFreezeOps(Boolean isKeepFreezeOps) {
this.isKeepFreezeOps = isKeepFreezeOps;
return this;
}
/**
* 获取 设备类型 (如果不指定,则默认注销所有客户端)
*
* @return deviceType /
*/
public String getDeviceType() {
return this.deviceType;
}
/**
* 设置 设备类型 (如果不指定,则默认注销所有客户端)
*
* @param deviceType /
* @return /
*/
public SaLogoutParameter setDeviceType(String deviceType) {
this.deviceType = deviceType;
return this;
}
/**
* 获取 注销类型
*
* @return logoutMode 注销类型
*/
public SaLogoutMode getMode() {
return this.mode;
}
/**
* 设置 注销类型
*
* @param mode 注销类型
* @return /
*/
public SaLogoutParameter setMode(SaLogoutMode mode) {
this.mode = mode;
return this;
}
/**
* 获取 注销范围 (此参数只在调用 StpUtil.logout(new SaLogoutParameter()) 时有效)
*
* @return /
*/
public SaLogoutRange getRange() {
return this.range;
}
/**
* 设置 注销范围 (此参数只在调用 StpUtil.logout(new SaLogoutParameter()) 时有效)
*
* @param range /
* @return /
*/
public SaLogoutParameter setRange(SaLogoutRange range) {
this.range = range;
return this;
}
/*
* toString
*/
@Override
public String toString() {
return "SaLoginParameter ["
+ "deviceType=" + deviceType
+ ", isKeepTokenSession=" + isKeepTokenSession
+ ", isKeepFreezeOps=" + isKeepFreezeOps
+ ", mode=" + mode
+ ", range=" + range
+ "]";
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.stp.parameter.enums;
/**
* SaLogoutMode: 注销模式
*
* @author click33
* @since 1.41.0
*/
public enum SaLogoutMode {
/**
* 注销下线
*/
LOGOUT,
/**
* 踢人下线
*/
KICKOUT,
/**
* 顶人下线
*/
REPLACED;
}
@@ -0,0 +1,36 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.stp.parameter.enums;
/**
* SaLogoutMode: 注销范围
*
* @author click33
* @since 1.41.0
*/
public enum SaLogoutRange {
/**
* token 范围:只注销提供的 token 指向的会话
*/
TOKEN,
/**
* 账号范围:注销 token 指向的 loginId 会话
*/
ACCOUNT
}
@@ -0,0 +1,36 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.stp.parameter.enums;
/**
* 顶人下线的范围
*
* @author click33
* @since 1.41.0
*/
public enum SaReplacedMode {
/**
* 当前指定的设备类型端
*/
CURR_DEVICE_TYPE,
/**
* 所有设备类型端
*/
ALL_DEVICE_TYPE
}
@@ -74,7 +74,7 @@ public class SaTokenConsts {
/** /**
* 常量 key 标记: 在登录时,默认使用的设备类型 * 常量 key 标记: 在登录时,默认使用的设备类型
*/ */
public static final String DEFAULT_LOGIN_DEVICE = "default-device"; public static final String DEFAULT_LOGIN_DEVICE_TYPE = "DEF";
/** /**
* 常量 key 标记: 在封禁账号时,默认封禁的服务类型 * 常量 key 标记: 在封禁账号时,默认封禁的服务类型
@@ -1,7 +1,7 @@
package com.pj.satoken; package com.pj.satoken;
import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
/** /**
* Sa-Token 自定义侦听器的实现 * Sa-Token 自定义侦听器的实现
@@ -5,7 +5,7 @@ import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.SaTerminalInfo; import cn.dev33.satoken.session.SaTerminalInfo;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
@@ -13,7 +13,7 @@ sa-token:
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true is-share: false
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik
token-style: uuid token-style: uuid
# 是否输出操作日志 # 是否输出操作日志
@@ -1,6 +1,6 @@
package com.pj.test; package com.pj.test;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
import com.pj.util.DeviceLockCheckUtil; import com.pj.util.DeviceLockCheckUtil;
@@ -13,7 +13,7 @@ sa-token:
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true is-share: false
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik
token-style: uuid token-style: uuid
# 是否输出操作日志 # 是否输出操作日志
+1 -1
View File
@@ -60,7 +60,7 @@
<artifactId>sa-token-redis-template</artifactId> <artifactId>sa-token-redis-template</artifactId>
<version>${sa-token.version}</version> <version>${sa-token.version}</version>
</dependency> </dependency>
<!-- 提供Redis连接池 --> <!-- 提供Redis连接池 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
@@ -4,7 +4,7 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.fun.SaFunction; import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
@@ -1,6 +1,7 @@
package com.pj.test; package com.pj.test;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -20,6 +21,7 @@ public class LoginController {
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对 // 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
if("zhang".equals(name) && "123456".equals(pwd)) { if("zhang".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001); StpUtil.login(10001);
StpUtil.getTokenSession();
return SaResult.ok("登录成功"); return SaResult.ok("登录成功");
} }
return SaResult.error("登录失败"); return SaResult.error("登录失败");
@@ -47,7 +49,7 @@ public class LoginController {
// 测试注销 ---- http://localhost:8081/acc/logout // 测试注销 ---- http://localhost:8081/acc/logout
@RequestMapping("logout") @RequestMapping("logout")
public SaResult logout() { public SaResult logout() {
StpUtil.logout(); StpUtil.login(10001, SaLoginParameter.create().setIsConcurrent(false));
return SaResult.ok(); return SaResult.ok();
} }
@@ -4,7 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckHttpDigest;
import cn.dev33.satoken.annotation.SaCheckSign; import cn.dev33.satoken.annotation.SaCheckSign;
import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.spring.SpringMVCUtil; import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
@@ -23,7 +23,7 @@ import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.jwt.error.SaJwtErrorCode; import cn.dev33.satoken.jwt.error.SaJwtErrorCode;
import cn.dev33.satoken.jwt.exception.SaJwtException; import cn.dev33.satoken.jwt.exception.SaJwtException;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
@@ -22,7 +22,7 @@ import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.jwt.error.SaJwtErrorCode; import cn.dev33.satoken.jwt.error.SaJwtErrorCode;
import cn.dev33.satoken.jwt.exception.SaJwtException; import cn.dev33.satoken.jwt.exception.SaJwtException;
import cn.dev33.satoken.listener.SaTokenEventCenter; import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
@@ -59,13 +59,13 @@ public class JwtForMixinTest {
Assertions.assertTrue(StpUtil.isLogin()); Assertions.assertTrue(StpUtil.isLogin());
Assertions.assertNotNull(token); // token不为null Assertions.assertNotNull(token); // token不为null
Assertions.assertEquals(StpUtil.getLoginIdAsLong(), 10001); // loginId=10001 Assertions.assertEquals(StpUtil.getLoginIdAsLong(), 10001); // loginId=10001
Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE); // 登录设备类型 Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE); // 登录设备类型
// token 验证 // token 验证
JWT jwt = JWT.of(token); JWT jwt = JWT.of(token);
JSONObject payloads = jwt.getPayloads(); JSONObject payloads = jwt.getPayloads();
Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_ID), "10001"); // 账号 Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_ID), "10001"); // 账号
Assertions.assertEquals(payloads.getStr(SaJwtUtil.DEVICE_TYPE), SaTokenConsts.DEFAULT_LOGIN_DEVICE); // 登录设备类型 Assertions.assertEquals(payloads.getStr(SaJwtUtil.DEVICE_TYPE), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE); // 登录设备类型
Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_TYPE), StpUtil.TYPE); // 账号类型 Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_TYPE), StpUtil.TYPE); // 账号类型
// db数据 验证 // db数据 验证
@@ -54,7 +54,7 @@ public class JwtForSimpleTest {
Assertions.assertTrue(StpUtil.isLogin()); Assertions.assertTrue(StpUtil.isLogin());
Assertions.assertNotNull(token); // token不为null Assertions.assertNotNull(token); // token不为null
Assertions.assertEquals(StpUtil.getLoginIdAsLong(), 10001); // loginId=10001 Assertions.assertEquals(StpUtil.getLoginIdAsLong(), 10001); // loginId=10001
Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE); // 登录设备类型 Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE); // 登录设备类型
// token 验证 // token 验证
JWT jwt = JWT.of(token); JWT jwt = JWT.of(token);
@@ -55,13 +55,13 @@ public class JwtForStatelessTest {
Assertions.assertTrue(StpUtil.isLogin()); Assertions.assertTrue(StpUtil.isLogin());
Assertions.assertNotNull(token); // token不为null Assertions.assertNotNull(token); // token不为null
Assertions.assertEquals(StpUtil.getLoginIdAsLong(), 10001); // loginId=10001 Assertions.assertEquals(StpUtil.getLoginIdAsLong(), 10001); // loginId=10001
Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE); // 登录设备类型 Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE); // 登录设备类型
// token 验证 // token 验证
JWT jwt = JWT.of(token); JWT jwt = JWT.of(token);
JSONObject payloads = jwt.getPayloads(); JSONObject payloads = jwt.getPayloads();
Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_ID), "10001"); // 账号 Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_ID), "10001"); // 账号
Assertions.assertEquals(payloads.getStr(SaJwtUtil.DEVICE_TYPE), SaTokenConsts.DEFAULT_LOGIN_DEVICE); // 登录设备类型 Assertions.assertEquals(payloads.getStr(SaJwtUtil.DEVICE_TYPE), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE); // 登录设备类型
Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_TYPE), StpUtil.TYPE); // 账号类型 Assertions.assertEquals(payloads.getStr(SaJwtUtil.LOGIN_TYPE), StpUtil.TYPE); // 账号类型
// 时间 // 时间
@@ -15,7 +15,7 @@
*/ */
package cn.dev33.satoken.core.stp; package cn.dev33.satoken.core.stp;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.util.SaTokenConsts; import cn.dev33.satoken.util.SaTokenConsts;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@@ -83,7 +83,7 @@ public class TokenInfoTest {
.create() .create()
.setTimeout(-1); .setTimeout(-1);
Assertions.assertEquals(loginParameter.getCookieTimeout(), Integer.MAX_VALUE); Assertions.assertEquals(loginParameter.getCookieTimeout(), Integer.MAX_VALUE);
Assertions.assertEquals(loginParameter.getDeviceOrDefault(), SaTokenConsts.DEFAULT_LOGIN_DEVICE); Assertions.assertEquals(loginParameter.getDeviceTypeOrDefault(), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE);
} }
} }
@@ -26,7 +26,7 @@ import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.spring.SpringMVCUtil; import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.spring.pathmatch.SaPathMatcherHolder; import cn.dev33.satoken.spring.pathmatch.SaPathMatcherHolder;
import cn.dev33.satoken.stp.SaLoginConfig; import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.SaLoginParameter; import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaTokenConsts; import cn.dev33.satoken.util.SaTokenConsts;
@@ -102,11 +102,11 @@ public class BasicsTest {
Assertions.assertNotNull(token); Assertions.assertNotNull(token);
Assertions.assertEquals(token, StpUtil.getTokenValueNotCut()); Assertions.assertEquals(token, StpUtil.getTokenValueNotCut());
Assertions.assertEquals(token, StpUtil.getTokenValueByLoginId(10001)); Assertions.assertEquals(token, StpUtil.getTokenValueByLoginId(10001));
Assertions.assertEquals(token, StpUtil.getTokenValueByLoginId(10001, SaTokenConsts.DEFAULT_LOGIN_DEVICE)); Assertions.assertEquals(token, StpUtil.getTokenValueByLoginId(10001, SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE));
// token 队列 // token 队列
List<String> tokenList = StpUtil.getTokenValueListByLoginId(10001); List<String> tokenList = StpUtil.getTokenValueListByLoginId(10001);
List<String> tokenList2 = StpUtil.getTokenValueListByLoginId(10001, SaTokenConsts.DEFAULT_LOGIN_DEVICE); List<String> tokenList2 = StpUtil.getTokenValueListByLoginId(10001, SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE);
Assertions.assertEquals(token, tokenList.get(tokenList.size() - 1)); Assertions.assertEquals(token, tokenList.get(tokenList.size() - 1));
Assertions.assertEquals(token, tokenList2.get(tokenList.size() - 1)); Assertions.assertEquals(token, tokenList2.get(tokenList.size() - 1));
@@ -119,7 +119,7 @@ public class BasicsTest {
Assertions.assertEquals(StpUtil.getLoginIdAsString(), "10001"); // loginId=10001 Assertions.assertEquals(StpUtil.getLoginIdAsString(), "10001"); // loginId=10001
Assertions.assertEquals(StpUtil.getLoginId(), "10001"); // loginId=10001 Assertions.assertEquals(StpUtil.getLoginId(), "10001"); // loginId=10001
Assertions.assertEquals(StpUtil.getLoginIdDefaultNull(), "10001"); // loginId=10001 Assertions.assertEquals(StpUtil.getLoginIdDefaultNull(), "10001"); // loginId=10001
Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE); // 登录设备类型 Assertions.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE_TYPE); // 登录设备类型
// db数据 验证 // db数据 验证
// token存在 // token存在