diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginInfo.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginInfo.java new file mode 100644 index 000000000..eb1d3c81f --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginInfo.java @@ -0,0 +1,126 @@ +package cn.dev33.satoken.stp; + +/** + * 登录信息 model + * + *
+ * { + * "tokenName": "satoekn", //request Header Name + * "tokenValue": "eef25f7b6c6048d093fc4427aa62f36c", //token + * "loginId": 10002, //login id + * "tokenTimeout": -1, //token 剩余有效期(单位: 秒) + * "sessionTimeout": -1, //Session 剩余有效时间(单位: 秒) + * "tokenSessionTimeout": -1, //Token-Session 剩余有效时间(单位: 秒) + * "tokenActiveTimeout": -1, //token 距离被冻结还剩多少时间(单位: 秒) + * "loginDevice": "Android-Readmi K50" //登录设备 + * } + *
+ * + * @author suzhelan + * @version 1.0 + */ +public class SaLoginInfo { + /** + * token name + */ + private String tokenName; + + /** + * token + */ + private String tokenValue; + + /** + * 此 token 对应的 LoginId + */ + private Object loginId; + + /** + * token 剩余有效期(单位: 秒) + */ + private long tokenTimeout; + + /** + * Account-Session 剩余有效时间(单位: 秒) + */ + private long sessionTimeout; + + /** + * Token-Session 剩余有效时间(单位: 秒) + */ + private long tokenSessionTimeout; + + /** + * token 距离被冻结还剩多少时间(单位: 秒) + */ + private long tokenActiveTimeout; + + /** + * 登录设备类型 + */ + private String loginDevice; + + public String getTokenName() { + return tokenName; + } + + public void setTokenName(String tokenName) { + this.tokenName = tokenName; + } + + public String getTokenValue() { + return tokenValue; + } + + public void setTokenValue(String tokenValue) { + this.tokenValue = tokenValue; + } + + public Object getLoginId() { + return loginId; + } + + public void setLoginId(Object loginId) { + this.loginId = loginId; + } + + public long getTokenTimeout() { + return tokenTimeout; + } + + public void setTokenTimeout(long tokenTimeout) { + this.tokenTimeout = tokenTimeout; + } + + public long getSessionTimeout() { + return sessionTimeout; + } + + public void setSessionTimeout(long sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + public long getTokenSessionTimeout() { + return tokenSessionTimeout; + } + + public void setTokenSessionTimeout(long tokenSessionTimeout) { + this.tokenSessionTimeout = tokenSessionTimeout; + } + + public long getTokenActiveTimeout() { + return tokenActiveTimeout; + } + + public void setTokenActiveTimeout(long tokenActiveTimeout) { + this.tokenActiveTimeout = tokenActiveTimeout; + } + + public String getLoginDevice() { + return loginDevice; + } + + public void setLoginDevice(String loginDevice) { + this.loginDevice = loginDevice; + } +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 3b6b4da0f..a56407a3a 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -36,6 +36,7 @@ import cn.dev33.satoken.util.SaTokenConsts; import cn.dev33.satoken.util.SaValue2Box; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -48,7 +49,7 @@ * Sa-Token 权限认证,逻辑实现类 * *- * Sa-Token 的核心,框架大多数功能均由此类提供具体逻辑实现。 + * Sa-Token 的核心,框架大多数功能均由此类提供具体逻辑实现。 *
* * @author click33 @@ -56,2885 +57,2926 @@ */ public class StpLogic { - /** - * 账号类型标识,多账号体系时(一个系统多套用户表)用此值区分具体要校验的是哪套用户,比如:login、user、admin - */ - public String loginType; - - /** - * 初始化 StpLogic, 并指定账号类型 - * - * @param loginType 账号类型标识 - */ - public StpLogic(String loginType) { - setLoginType(loginType); - } - - /** - * 获取当前 StpLogic 账号类型标识 - * - * @return / - */ - public String getLoginType(){ - return loginType; - } - - /** - * 安全的重置当前账号类型 - * - * @param loginType 账号类型标识 - * @return 对象自身 - */ - public StpLogic setLoginType(String loginType){ - - // 先清除此 StpLogic 在全局 SaManager 中的记录 - if(SaFoxUtil.isNotEmpty(this.loginType)) { - SaManager.removeStpLogic(this.loginType); - } - - // 赋值 - this.loginType = loginType; - - // 将新的 loginType -> StpLogic 映射关系 put 到 SaManager 全局集合中,以便后续根据 LoginType 进行查找此对象 - SaManager.putStpLogic(this); - - return this; - } - - private SaTokenConfig config; - - /** - * 写入当前 StpLogic 单独使用的配置对象 - * - * @param config 配置对象 - * @return 对象自身 - */ - public StpLogic setConfig(SaTokenConfig config) { - this.config = config; - return this; - } - - /** - * 返回当前 StpLogic 使用的配置对象,如果当前 StpLogic 没有配置,则返回 null - * - * @return / - */ - public SaTokenConfig getConfig() { - return config; - } - - /** - * 返回当前 StpLogic 使用的配置对象,如果当前 StpLogic 没有配置,则返回全局配置对象 - * - * @return / - */ - public SaTokenConfig getConfigOrGlobal() { - SaTokenConfig cfg = getConfig(); - if(cfg != null) { - return cfg; - } - return SaManager.getConfig(); - } - - - - // ------------------- 获取 token 相关 ------------------- - - /** - * 返回 token 名称,此名称在以下地方体现:Cookie 保存 token 时的名称、提交 token 时参数的名称、存储 token 时的 key 前缀 - * - * @return / - */ - public String getTokenName() { - return splicingKeyTokenName(); - } - - /** - * 为指定账号创建一个 token (只是把 token 创建出来,并不持久化存储) - * - * @param loginId 账号id - * @param device 设备类型 - * @param timeout 过期时间 - * @param extraData 扩展信息 - * @return 生成的tokenValue - */ - public String createTokenValue(Object loginId, String device, long timeout, Map当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5
- * - * @param loginId 账号id - */ - public void kickout(Object loginId) { - kickout(loginId, null); - } - - /** - * 踢人下线,根据账号id 和 设备类型 - *当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5
- * - * @param loginId 账号id - * @param device 设备类型 (填 null 代表踢出该账号的所有设备类型) - */ - public void kickout(Object loginId, String device) { - // 1、获取此账号的 Account-Session,上面记录了此账号的所有登录客户端数据 - SaSession session = getSessionByLoginId(loginId, false); - if(session != null) { - - // 2、遍历此账号所有从这个 device 设备上登录的客户端,清除相关数据 - for (TokenSign tokenSign: session.getTokenSignListByDevice(device)) { - - // 2.1、获取此客户端的 token 值 - String tokenValue = tokenSign.getValue(); - - // 2.2、从 Account-Session 上清除 token 签名 - session.removeTokenSign(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.logoutByTokenSignCountToZero(); - } - } - - /** - * 踢人下线,根据指定 token - *当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5
- * - * @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 上的 token 签名,并且尝试注销掉 Account-Session - SaSession session = getSessionByLoginId(loginId, false); - if(session != null) { - session.removeTokenSign(tokenValue); - session.logoutByTokenSignCountToZero(); - } - } - - /** - * 顶人下线,根据账号id 和 设备类型 - *当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4
- * - * @param loginId 账号id - * @param device 设备类型 (填 null 代表顶替该账号的所有设备类型) - */ - public void replaced(Object loginId, String device) { - // 1、获取此账号的 Account-Session,上面记录了此账号的所有登录客户端数据 - SaSession session = getSessionByLoginId(loginId, false); - if(session != null) { - - // 2、遍历此账号所有从这个 device 设备上登录的客户端,清除相关数据 - for (TokenSign tokenSign: session.getTokenSignListByDevice(device)) { - - // 2.1、获取此客户端的 token 值 - String tokenValue = tokenSign.getValue(); - - // 2.2、从 Account-Session 上清除 token 签名 - session.removeTokenSign(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 - // session.logoutByTokenSignCountToZero(); - } - } - - // ---- 会话查询 - - /** - * 判断当前会话是否已经登录 - * - * @return 已登录返回 true,未登录返回 false - */ - public boolean isLogin() { - // 判断条件: - // 1、获取到的 loginId 不为 null, - // 2、并且不在异常项集合里(此项在 getLoginIdDefaultNull() 方法里完成判断) - return getLoginIdDefaultNull() != null; - } - - /** - * 判断指定账号是否已经登录 - * - * @return 已登录返回 true,未登录返回 false - */ - public boolean isLogin(Object loginId) { - // 判断条件:能否根据 loginId 查询到对应的 tokenSign 值 - return getTokenSignListByLoginId(loginId, null).size() > 0; - } - - /** - * 检验当前会话是否已经登录,如未登录,则抛出异常 - */ - public void checkLogin() { - // 效果与 getLoginId() 相同,只是 checkLogin() 更加语义化一些 - getLoginId(); - } - - /** - * 获取当前会话账号id,如果未登录,则抛出异常 - * - * @return 账号id - */ - public Object getLoginId() { - - // 1、先判断一下当前会话是否正在 [ 临时身份切换 ], 如果是则返回临时身份 - if(isSwitch()) { - return getSwitchLoginId(); - } - - // 2、如果前端没有提交 token,则抛出异常: 未能读取到有效 token - String tokenValue = getTokenValue(true); - if(SaFoxUtil.isEmpty(tokenValue)) { - throw NotLoginException.newInstance(loginType, NOT_TOKEN, NOT_TOKEN_MESSAGE, null).setCode(SaErrorCode.CODE_11011); - } - - // 3、查找此 token 对应的 loginId,如果找不到则抛出:token 无效 - String loginId = getLoginIdNotHandle(tokenValue); - if(SaFoxUtil.isEmpty(loginId)) { - throw NotLoginException.newInstance(loginType, INVALID_TOKEN, INVALID_TOKEN_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11012); - } - - // 4、如果这个 token 指向的是值是:过期标记,则抛出:token 已过期 - if(loginId.equals(NotLoginException.TOKEN_TIMEOUT)) { - throw NotLoginException.newInstance(loginType, TOKEN_TIMEOUT, TOKEN_TIMEOUT_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11013); - } - - // 5、如果这个 token 指向的是值是:被顶替标记,则抛出:token 已被顶下线 - if(loginId.equals(NotLoginException.BE_REPLACED)) { - throw NotLoginException.newInstance(loginType, BE_REPLACED, BE_REPLACED_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11014); - } - - // 6、如果这个 token 指向的是值是:被踢下线标记,则抛出:token 已被踢下线 - if(loginId.equals(NotLoginException.KICK_OUT)) { - throw NotLoginException.newInstance(loginType, KICK_OUT, KICK_OUT_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11015); - } - - // 7、检查此 token 的最后活跃时间是否已经超过了 active-timeout 的限制,如果是则代表其已被冻结,需要抛出:token 已被冻结 - if(isOpenCheckActiveTimeout()) { - checkActiveTimeout(tokenValue); - - // ------ 至此,loginId 已经是一个合法的值,代表当前会话是一个正常的登录状态了 - - // 8、如果配置了自动续签功能, 则: 更新这个 token 的最后活跃时间 (注意此处的续签是在续 active-timeout,而非 timeout) - if(getConfigOrGlobal().getAutoRenew()) { - updateLastActiveToNow(tokenValue); - } - } - - // 9、返回 loginId - return loginId; - } - - /** - * 获取当前会话账号id, 如果未登录,则返回默认值 - * - * @param- * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token, - * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId - *
- * - * @param loginId 账号id - * @return token值 - */ - public String getTokenValueByLoginId(Object loginId) { - return getTokenValueByLoginId(loginId, null); - } - - /** - * 获取指定账号 id 指定设备类型端的 token - *- * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token, - * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId - *
- * - * @param loginId 账号id - * @param device 设备类型,填 null 代表不限设备类型 - * @return token值 - */ - public String getTokenValueByLoginId(Object loginId, String device) { - List此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) - * - * @param loginId 指定账号id - * @param time 封禁时间, 单位: 秒 (-1=永久封禁) - */ - public void disable(Object loginId, long time) { - disableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.DEFAULT_DISABLE_LEVEL, time); - } - - /** - * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁) - * - * @param loginId 账号id - * @return / - */ - public boolean isDisable(Object loginId) { - return isDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.MIN_DISABLE_LEVEL); - } - - /** - * 校验:指定账号是否已被封禁,如果被封禁则抛出异常 - * - * @param loginId 账号id - */ - public void checkDisable(Object loginId) { - checkDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.MIN_DISABLE_LEVEL); - } - - /** - * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) - * - * @param loginId 账号id - * @return / - */ - public long getDisableTime(Object loginId) { - return getDisableTime(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE); - } - - /** - * 解封:指定账号 - * - * @param loginId 账号id - */ - public void untieDisable(Object loginId) { - untieDisable(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE); - } - - - // ------------------- 分类封禁 ------------------- - - /** - * 封禁:指定账号的指定服务 - *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
- *
- * @param loginId 指定账号id
- * @param service 指定服务
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public void disable(Object loginId, String service, long time) {
- disableLevel(loginId, service, SaTokenConsts.DEFAULT_DISABLE_LEVEL, time);
- }
-
- /**
- * 判断:指定账号的指定服务 是否已被封禁(true=已被封禁, false=未被封禁)
- *
- * @param loginId 账号id
- * @param service 指定服务
- * @return /
- */
- public boolean isDisable(Object loginId, String service) {
- return isDisableLevel(loginId, service, SaTokenConsts.MIN_DISABLE_LEVEL);
- }
-
- /**
- * 校验:指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常
- *
- * @param loginId 账号id
- * @param services 指定服务,可以指定多个
- */
- public void checkDisable(Object loginId, String... services) {
- if(services != null) {
- for (String service : services) {
- checkDisableLevel(loginId, service, SaTokenConsts.MIN_DISABLE_LEVEL);
- }
- }
- }
-
- /**
- * 获取:指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
- *
- * @param loginId 账号id
- * @param service 指定服务
- * @return see note
- */
- public long getDisableTime(Object loginId, String service) {
- return getSaTokenDao().getTimeout(splicingKeyDisable(loginId, service));
- }
-
- /**
- * 解封:指定账号、指定服务
- *
- * @param loginId 账号id
- * @param services 指定服务,可以指定多个
- */
- public void untieDisable(Object loginId, String... services) {
-
- // 先检查提供的参数是否有效
- if(SaFoxUtil.isEmpty(loginId)) {
- throw new SaTokenException("请提供要解禁的账号").setCode(SaErrorCode.CODE_11062);
- }
- if(services == null || services.length == 0) {
- throw new SaTokenException("请提供要解禁的服务").setCode(SaErrorCode.CODE_11063);
- }
-
- // 遍历逐个解禁
- for (String service : services) {
- // 解封
- getSaTokenDao().delete(splicingKeyDisable(loginId, service));
-
- // $$ 发布事件
- SaTokenEventCenter.doUntieDisable(loginType, loginId, service);
- }
- }
-
-
- // ------------------- 阶梯封禁 -------------------
-
- /**
- * 封禁:指定账号,并指定封禁等级
- *
- * @param loginId 指定账号id
- * @param level 指定封禁等级
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public void disableLevel(Object loginId, int level, long time) {
- disableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, level, time);
- }
-
- /**
- * 封禁:指定账号的指定服务,并指定封禁等级
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @param level 指定封禁等级
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public void disableLevel(Object loginId, String service, int level, long time) {
- // 先检查提供的参数是否有效
- if(SaFoxUtil.isEmpty(loginId)) {
- throw new SaTokenException("请提供要封禁的账号").setCode(SaErrorCode.CODE_11062);
- }
- if(SaFoxUtil.isEmpty(service)) {
- throw new SaTokenException("请提供要封禁的服务").setCode(SaErrorCode.CODE_11063);
- }
- if(level < SaTokenConsts.MIN_DISABLE_LEVEL) {
- throw new SaTokenException("封禁等级不可以小于最小值:" + SaTokenConsts.MIN_DISABLE_LEVEL).setCode(SaErrorCode.CODE_11064);
- }
-
- // 打上封禁标记
- getSaTokenDao().set(splicingKeyDisable(loginId, service), String.valueOf(level), time);
-
- // $$ 发布事件
- SaTokenEventCenter.doDisable(loginType, loginId, service, level, time);
- }
-
- /**
- * 判断:指定账号是否已被封禁到指定等级
- *
- * @param loginId 指定账号id
- * @param level 指定封禁等级
- * @return /
- */
- public boolean isDisableLevel(Object loginId, int level) {
- return isDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, level);
- }
-
- /**
- * 判断:指定账号的指定服务,是否已被封禁到指定等级
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @param level 指定封禁等级
- * @return /
- */
- public boolean isDisableLevel(Object loginId, String service, int level) {
- // 1、先前置检查一下这个账号是否被封禁了
- int disableLevel = getDisableLevel(loginId, service);
- if(disableLevel == SaTokenConsts.NOT_DISABLE_LEVEL) {
- return false;
- }
-
- // 2、再判断被封禁的等级是否达到了指定级别
- return disableLevel >= level;
- }
-
- /**
- * 校验:指定账号是否已被封禁到指定等级(如果已经达到,则抛出异常)
- *
- * @param loginId 指定账号id
- * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
- */
- public void checkDisableLevel(Object loginId, int level) {
- checkDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, level);
- }
-
- /**
- * 校验:指定账号的指定服务,是否已被封禁到指定等级(如果已经达到,则抛出异常)
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
- */
- public void checkDisableLevel(Object loginId, String service, int level) {
- // 1、先前置检查一下这个账号是否被封禁了
- String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));
- if(SaFoxUtil.isEmpty(value)) {
- return;
- }
-
- // 2、再判断被封禁的等级是否达到了指定级别
- Integer disableLevel = SaFoxUtil.getValueByType(value, int.class);
- if(disableLevel >= level) {
- throw new DisableServiceException(loginType, loginId, service, disableLevel, level, getDisableTime(loginId, service))
- .setCode(SaErrorCode.CODE_11061);
- }
- }
-
- /**
- * 获取:指定账号被封禁的等级,如果未被封禁则返回-2
- *
- * @param loginId 指定账号id
- * @return /
- */
- public int getDisableLevel(Object loginId) {
- return getDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE);
- }
-
- /**
- * 获取:指定账号的 指定服务 被封禁的等级,如果未被封禁则返回-2
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @return /
- */
- public int getDisableLevel(Object loginId, String service) {
- // 1、判断是否被封禁了,如果尚未被封禁,返回-2
- String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));
- if(SaFoxUtil.isEmpty(value)) {
- return SaTokenConsts.NOT_DISABLE_LEVEL;
- }
-
- // 2、转为 int 类型返回
- return SaFoxUtil.getValueByType(value, int.class);
- }
-
-
- // ------------------- 临时身份切换 -------------------
-
- /**
- * 临时切换身份为指定账号id
- *
- * @param loginId 指定loginId
- */
- public void switchTo(Object loginId) {
- SaHolder.getStorage().set(splicingKeySwitch(), loginId);
- }
-
- /**
- * 结束临时切换身份
- */
- public void endSwitch() {
- SaHolder.getStorage().delete(splicingKeySwitch());
- }
-
- /**
- * 判断当前请求是否正处于 [ 身份临时切换 ] 中
- *
- * @return /
- */
- public boolean isSwitch() {
- return SaHolder.getStorage().get(splicingKeySwitch()) != null;
- }
-
- /**
- * 返回 [ 身份临时切换 ] 的 loginId
- *
- * @return /
- */
- public Object getSwitchLoginId() {
- return SaHolder.getStorage().get(splicingKeySwitch());
- }
-
- /**
- * 在一个 lambda 代码段里,临时切换身份为指定账号id,lambda 结束后自动恢复
- *
- * @param loginId 指定账号id
- * @param function 要执行的方法
- */
- public void switchTo(Object loginId, SaFunction function) {
- try {
- switchTo(loginId);
- function.run();
- } finally {
- endSwitch();
- }
- }
-
-
- // ------------------- 二级认证 -------------------
-
- /**
- * 在当前会话 开启二级认证
- *
- * @param safeTime 维持时间 (单位: 秒)
- */
- public void openSafe(long safeTime) {
- openSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE, safeTime);
- }
-
- /**
- * 在当前会话 开启二级认证
- *
- * @param service 业务标识
- * @param safeTime 维持时间 (单位: 秒)
- */
- public void openSafe(String service, long safeTime) {
- // 1、开启二级认证前必须处于登录状态,否则抛出异常
- checkLogin();
-
- // 2、写入指定的 可以 标记,打开二级认证
- String tokenValue = getTokenValueNotNull();
- getSaTokenDao().set(splicingKeySafe(tokenValue, service), SaTokenConsts.SAFE_AUTH_SAVE_VALUE, safeTime);
-
- // 3、$$ 发布事件,某某 token 令牌开启了二级认证
- SaTokenEventCenter.doOpenSafe(loginType, tokenValue, service, safeTime);
- }
-
- /**
- * 判断:当前会话是否处于二级认证时间内
- *
- * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
- */
- public boolean isSafe() {
- return isSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
- }
-
- /**
- * 判断:当前会话 是否处于指定业务的二级认证时间内
- *
- * @param service 业务标识
- * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
- */
- public boolean isSafe(String service) {
- return isSafe(getTokenValue(), service);
- }
-
- /**
- * 判断:指定 token 是否处于二级认证时间内
- *
- * @param tokenValue Token 值
- * @param service 业务标识
- * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
- */
- public boolean isSafe(String tokenValue, String service) {
- // 1、如果提供的 Token 为空,则直接视为未认证
- if(SaFoxUtil.isEmpty(tokenValue)) {
- return false;
- }
-
- // 2、如果此 token 不处于登录状态,也将其视为未认证
- Object loginId = getLoginIdNotHandle(tokenValue);
- if( ! isValidLoginId(loginId) ) {
- return false;
- }
-
- // 3、如果缓存中可以查询出指定的键值,则代表已认证,否则视为未认证
- String value = getSaTokenDao().get(splicingKeySafe(tokenValue, service));
- return !(SaFoxUtil.isEmpty(value));
- }
-
- /**
- * 校验:当前会话是否已通过二级认证,如未通过则抛出异常
- */
- public void checkSafe() {
- checkSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
- }
-
- /**
- * 校验:检查当前会话是否已通过指定业务的二级认证,如未通过则抛出异常
- *
- * @param service 业务标识
- */
- public void checkSafe(String service) {
- // 1、必须先通过登录校验
- checkLogin();
-
- // 2、再进行二级认证校验
- // 如果缓存中可以查询出指定的键值,则代表已认证,否则视为未认证
- String tokenValue = getTokenValue();
- String value = getSaTokenDao().get(splicingKeySafe(tokenValue, service));
- if(SaFoxUtil.isEmpty(value)) {
- throw new NotSafeException(loginType, tokenValue, service).setCode(SaErrorCode.CODE_11071);
- }
- }
-
- /**
- * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
- *
- * @return 剩余有效时间
- */
- public long getSafeTime() {
- return getSafeTime(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
- }
-
- /**
- * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
- *
- * @param service 业务标识
- * @return 剩余有效时间
- */
- public long getSafeTime(String service) {
- // 1、如果前端没有提交 Token,则直接视为未认证
- String tokenValue = getTokenValue();
- if(SaFoxUtil.isEmpty(tokenValue)) {
- return SaTokenDao.NOT_VALUE_EXPIRE;
- }
-
- // 2、从缓存中查询这个 key 的剩余有效期
- return getSaTokenDao().getTimeout(splicingKeySafe(tokenValue, service));
- }
-
- /**
- * 在当前会话 结束二级认证
- */
- public void closeSafe() {
- closeSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
- }
-
- /**
- * 在当前会话 结束指定业务标识的二级认证
- *
- * @param service 业务标识
- */
- public void closeSafe(String service) {
- // 1、如果前端没有提交 Token,则无需任何操作
- String tokenValue = getTokenValue();
- if(SaFoxUtil.isEmpty(tokenValue)) {
- return;
- }
-
- // 2、删除 key
- getSaTokenDao().delete(splicingKeySafe(tokenValue, service));
-
- // 3、$$ 发布事件,某某 token 令牌关闭了二级认证
- SaTokenEventCenter.doCloseSafe(loginType, tokenValue, service);
- }
-
-
- // ------------------- 拼接相应key -------------------
-
- /**
- * 获取:客户端 tokenName
- *
- * @return key
- */
- public String splicingKeyTokenName() {
- return getConfigOrGlobal().getTokenName();
- }
-
- /**
- * 拼接: 在保存 token - id 映射关系时,应该使用的key
- *
- * @param tokenValue token值
- * @return key
- */
- public String splicingKeyTokenValue(String tokenValue) {
- return getConfigOrGlobal().getTokenName() + ":" + loginType + ":token:" + tokenValue;
- }
-
- /**
- * 拼接: 在保存 Account-Session 时,应该使用的 key
- *
- * @param loginId 账号id
- * @return key
- */
- public String splicingKeySession(Object loginId) {
- return getConfigOrGlobal().getTokenName() + ":" + loginType + ":session:" + loginId;
- }
-
- /**
- * 拼接:在保存 Token-Session 时,应该使用的 key
- *
- * @param tokenValue token值
- * @return key
- */
- public String splicingKeyTokenSession(String tokenValue) {
- return getConfigOrGlobal().getTokenName() + ":" + loginType + ":token-session:" + tokenValue;
- }
-
- /**
- * 拼接: 在保存 token 最后活跃时间时,应该使用的 key
- *
- * @param tokenValue token值
- * @return key
- */
- public String splicingKeyLastActiveTime(String tokenValue) {
- return getConfigOrGlobal().getTokenName() + ":" + loginType + ":last-active:" + tokenValue;
- }
-
- /**
- * 拼接:在进行临时身份切换时,应该使用的 key
- *
- * @return key
- */
- public String splicingKeySwitch() {
- return SaTokenConsts.SWITCH_TO_SAVE_KEY + loginType;
- }
-
- /**
- * 如果 token 为本次请求新创建的,则以此字符串为 key 存储在当前 request 中
- *
- * @return key
- */
- public String splicingKeyJustCreatedSave() {
+ /**
+ * 账号类型标识,多账号体系时(一个系统多套用户表)用此值区分具体要校验的是哪套用户,比如:login、user、admin
+ */
+ public String loginType;
+
+ /**
+ * 初始化 StpLogic, 并指定账号类型
+ *
+ * @param loginType 账号类型标识
+ */
+ public StpLogic(String loginType) {
+ setLoginType(loginType);
+ }
+
+ /**
+ * 获取当前 StpLogic 账号类型标识
+ *
+ * @return /
+ */
+ public String getLoginType() {
+ return loginType;
+ }
+
+ /**
+ * 安全的重置当前账号类型
+ *
+ * @param loginType 账号类型标识
+ * @return 对象自身
+ */
+ public StpLogic setLoginType(String loginType) {
+
+ // 先清除此 StpLogic 在全局 SaManager 中的记录
+ if (SaFoxUtil.isNotEmpty(this.loginType)) {
+ SaManager.removeStpLogic(this.loginType);
+ }
+
+ // 赋值
+ this.loginType = loginType;
+
+ // 将新的 loginType -> StpLogic 映射关系 put 到 SaManager 全局集合中,以便后续根据 LoginType 进行查找此对象
+ SaManager.putStpLogic(this);
+
+ return this;
+ }
+
+ private SaTokenConfig config;
+
+ /**
+ * 写入当前 StpLogic 单独使用的配置对象
+ *
+ * @param config 配置对象
+ * @return 对象自身
+ */
+ public StpLogic setConfig(SaTokenConfig config) {
+ this.config = config;
+ return this;
+ }
+
+ /**
+ * 返回当前 StpLogic 使用的配置对象,如果当前 StpLogic 没有配置,则返回 null
+ *
+ * @return /
+ */
+ public SaTokenConfig getConfig() {
+ return config;
+ }
+
+ /**
+ * 返回当前 StpLogic 使用的配置对象,如果当前 StpLogic 没有配置,则返回全局配置对象
+ *
+ * @return /
+ */
+ public SaTokenConfig getConfigOrGlobal() {
+ SaTokenConfig cfg = getConfig();
+ if (cfg != null) {
+ return cfg;
+ }
+ return SaManager.getConfig();
+ }
+
+ // ------------------- 获取 登录信息 相关 -------------------
+
+ /**
+ * 获取当前账号的所有登录信息
+ *
+ * @return 当前账号登录信息列表
+ */
+ public List 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4
+ * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token,
+ * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId
+ *
+ * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token,
+ * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId
+ * 此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
+ *
+ * @param loginId 指定账号id
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public void disable(Object loginId, long time) {
+ disableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.DEFAULT_DISABLE_LEVEL, time);
+ }
+
+ /**
+ * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
+ *
+ * @param loginId 账号id
+ * @return /
+ */
+ public boolean isDisable(Object loginId) {
+ return isDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.MIN_DISABLE_LEVEL);
+ }
+
+ /**
+ * 校验:指定账号是否已被封禁,如果被封禁则抛出异常
+ *
+ * @param loginId 账号id
+ */
+ public void checkDisable(Object loginId) {
+ checkDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.MIN_DISABLE_LEVEL);
+ }
+
+ /**
+ * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
+ *
+ * @param loginId 账号id
+ * @return /
+ */
+ public long getDisableTime(Object loginId) {
+ return getDisableTime(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE);
+ }
+
+ /**
+ * 解封:指定账号
+ *
+ * @param loginId 账号id
+ */
+ public void untieDisable(Object loginId) {
+ untieDisable(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE);
+ }
+
+
+ // ------------------- 分类封禁 -------------------
+
+ /**
+ * 封禁:指定账号的指定服务
+ * 此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
+ *
+ * @param loginId 指定账号id
+ * @param service 指定服务
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public void disable(Object loginId, String service, long time) {
+ disableLevel(loginId, service, SaTokenConsts.DEFAULT_DISABLE_LEVEL, time);
+ }
+
+ /**
+ * 判断:指定账号的指定服务 是否已被封禁(true=已被封禁, false=未被封禁)
+ *
+ * @param loginId 账号id
+ * @param service 指定服务
+ * @return /
+ */
+ public boolean isDisable(Object loginId, String service) {
+ return isDisableLevel(loginId, service, SaTokenConsts.MIN_DISABLE_LEVEL);
+ }
+
+ /**
+ * 校验:指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常
+ *
+ * @param loginId 账号id
+ * @param services 指定服务,可以指定多个
+ */
+ public void checkDisable(Object loginId, String... services) {
+ if (services != null) {
+ for (String service : services) {
+ checkDisableLevel(loginId, service, SaTokenConsts.MIN_DISABLE_LEVEL);
+ }
+ }
+ }
+
+ /**
+ * 获取:指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
+ *
+ * @param loginId 账号id
+ * @param service 指定服务
+ * @return see note
+ */
+ public long getDisableTime(Object loginId, String service) {
+ return getSaTokenDao().getTimeout(splicingKeyDisable(loginId, service));
+ }
+
+ /**
+ * 解封:指定账号、指定服务
+ *
+ * @param loginId 账号id
+ * @param services 指定服务,可以指定多个
+ */
+ public void untieDisable(Object loginId, String... services) {
+
+ // 先检查提供的参数是否有效
+ if (SaFoxUtil.isEmpty(loginId)) {
+ throw new SaTokenException("请提供要解禁的账号").setCode(SaErrorCode.CODE_11062);
+ }
+ if (services == null || services.length == 0) {
+ throw new SaTokenException("请提供要解禁的服务").setCode(SaErrorCode.CODE_11063);
+ }
+
+ // 遍历逐个解禁
+ for (String service : services) {
+ // 解封
+ getSaTokenDao().delete(splicingKeyDisable(loginId, service));
+
+ // $$ 发布事件
+ SaTokenEventCenter.doUntieDisable(loginType, loginId, service);
+ }
+ }
+
+
+ // ------------------- 阶梯封禁 -------------------
+
+ /**
+ * 封禁:指定账号,并指定封禁等级
+ *
+ * @param loginId 指定账号id
+ * @param level 指定封禁等级
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public void disableLevel(Object loginId, int level, long time) {
+ disableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, level, time);
+ }
+
+ /**
+ * 封禁:指定账号的指定服务,并指定封禁等级
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @param level 指定封禁等级
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public void disableLevel(Object loginId, String service, int level, long time) {
+ // 先检查提供的参数是否有效
+ if (SaFoxUtil.isEmpty(loginId)) {
+ throw new SaTokenException("请提供要封禁的账号").setCode(SaErrorCode.CODE_11062);
+ }
+ if (SaFoxUtil.isEmpty(service)) {
+ throw new SaTokenException("请提供要封禁的服务").setCode(SaErrorCode.CODE_11063);
+ }
+ if (level < SaTokenConsts.MIN_DISABLE_LEVEL) {
+ throw new SaTokenException("封禁等级不可以小于最小值:" + SaTokenConsts.MIN_DISABLE_LEVEL).setCode(SaErrorCode.CODE_11064);
+ }
+
+ // 打上封禁标记
+ getSaTokenDao().set(splicingKeyDisable(loginId, service), String.valueOf(level), time);
+
+ // $$ 发布事件
+ SaTokenEventCenter.doDisable(loginType, loginId, service, level, time);
+ }
+
+ /**
+ * 判断:指定账号是否已被封禁到指定等级
+ *
+ * @param loginId 指定账号id
+ * @param level 指定封禁等级
+ * @return /
+ */
+ public boolean isDisableLevel(Object loginId, int level) {
+ return isDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, level);
+ }
+
+ /**
+ * 判断:指定账号的指定服务,是否已被封禁到指定等级
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @param level 指定封禁等级
+ * @return /
+ */
+ public boolean isDisableLevel(Object loginId, String service, int level) {
+ // 1、先前置检查一下这个账号是否被封禁了
+ int disableLevel = getDisableLevel(loginId, service);
+ if (disableLevel == SaTokenConsts.NOT_DISABLE_LEVEL) {
+ return false;
+ }
+
+ // 2、再判断被封禁的等级是否达到了指定级别
+ return disableLevel >= level;
+ }
+
+ /**
+ * 校验:指定账号是否已被封禁到指定等级(如果已经达到,则抛出异常)
+ *
+ * @param loginId 指定账号id
+ * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
+ */
+ public void checkDisableLevel(Object loginId, int level) {
+ checkDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, level);
+ }
+
+ /**
+ * 校验:指定账号的指定服务,是否已被封禁到指定等级(如果已经达到,则抛出异常)
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
+ */
+ public void checkDisableLevel(Object loginId, String service, int level) {
+ // 1、先前置检查一下这个账号是否被封禁了
+ String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));
+ if (SaFoxUtil.isEmpty(value)) {
+ return;
+ }
+
+ // 2、再判断被封禁的等级是否达到了指定级别
+ Integer disableLevel = SaFoxUtil.getValueByType(value, int.class);
+ if (disableLevel >= level) {
+ throw new DisableServiceException(loginType, loginId, service, disableLevel, level, getDisableTime(loginId, service))
+ .setCode(SaErrorCode.CODE_11061);
+ }
+ }
+
+ /**
+ * 获取:指定账号被封禁的等级,如果未被封禁则返回-2
+ *
+ * @param loginId 指定账号id
+ * @return /
+ */
+ public int getDisableLevel(Object loginId) {
+ return getDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE);
+ }
+
+ /**
+ * 获取:指定账号的 指定服务 被封禁的等级,如果未被封禁则返回-2
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @return /
+ */
+ public int getDisableLevel(Object loginId, String service) {
+ // 1、判断是否被封禁了,如果尚未被封禁,返回-2
+ String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));
+ if (SaFoxUtil.isEmpty(value)) {
+ return SaTokenConsts.NOT_DISABLE_LEVEL;
+ }
+
+ // 2、转为 int 类型返回
+ return SaFoxUtil.getValueByType(value, int.class);
+ }
+
+
+ // ------------------- 临时身份切换 -------------------
+
+ /**
+ * 临时切换身份为指定账号id
+ *
+ * @param loginId 指定loginId
+ */
+ public void switchTo(Object loginId) {
+ SaHolder.getStorage().set(splicingKeySwitch(), loginId);
+ }
+
+ /**
+ * 结束临时切换身份
+ */
+ public void endSwitch() {
+ SaHolder.getStorage().delete(splicingKeySwitch());
+ }
+
+ /**
+ * 判断当前请求是否正处于 [ 身份临时切换 ] 中
+ *
+ * @return /
+ */
+ public boolean isSwitch() {
+ return SaHolder.getStorage().get(splicingKeySwitch()) != null;
+ }
+
+ /**
+ * 返回 [ 身份临时切换 ] 的 loginId
+ *
+ * @return /
+ */
+ public Object getSwitchLoginId() {
+ return SaHolder.getStorage().get(splicingKeySwitch());
+ }
+
+ /**
+ * 在一个 lambda 代码段里,临时切换身份为指定账号id,lambda 结束后自动恢复
+ *
+ * @param loginId 指定账号id
+ * @param function 要执行的方法
+ */
+ public void switchTo(Object loginId, SaFunction function) {
+ try {
+ switchTo(loginId);
+ function.run();
+ } finally {
+ endSwitch();
+ }
+ }
+
+
+ // ------------------- 二级认证 -------------------
+
+ /**
+ * 在当前会话 开启二级认证
+ *
+ * @param safeTime 维持时间 (单位: 秒)
+ */
+ public void openSafe(long safeTime) {
+ openSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE, safeTime);
+ }
+
+ /**
+ * 在当前会话 开启二级认证
+ *
+ * @param service 业务标识
+ * @param safeTime 维持时间 (单位: 秒)
+ */
+ public void openSafe(String service, long safeTime) {
+ // 1、开启二级认证前必须处于登录状态,否则抛出异常
+ checkLogin();
+
+ // 2、写入指定的 可以 标记,打开二级认证
+ String tokenValue = getTokenValueNotNull();
+ getSaTokenDao().set(splicingKeySafe(tokenValue, service), SaTokenConsts.SAFE_AUTH_SAVE_VALUE, safeTime);
+
+ // 3、$$ 发布事件,某某 token 令牌开启了二级认证
+ SaTokenEventCenter.doOpenSafe(loginType, tokenValue, service, safeTime);
+ }
+
+ /**
+ * 判断:当前会话是否处于二级认证时间内
+ *
+ * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+ */
+ public boolean isSafe() {
+ return isSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
+ }
+
+ /**
+ * 判断:当前会话 是否处于指定业务的二级认证时间内
+ *
+ * @param service 业务标识
+ * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+ */
+ public boolean isSafe(String service) {
+ return isSafe(getTokenValue(), service);
+ }
+
+ /**
+ * 判断:指定 token 是否处于二级认证时间内
+ *
+ * @param tokenValue Token 值
+ * @param service 业务标识
+ * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+ */
+ public boolean isSafe(String tokenValue, String service) {
+ // 1、如果提供的 Token 为空,则直接视为未认证
+ if (SaFoxUtil.isEmpty(tokenValue)) {
+ return false;
+ }
+
+ // 2、如果此 token 不处于登录状态,也将其视为未认证
+ Object loginId = getLoginIdNotHandle(tokenValue);
+ if (!isValidLoginId(loginId)) {
+ return false;
+ }
+
+ // 3、如果缓存中可以查询出指定的键值,则代表已认证,否则视为未认证
+ String value = getSaTokenDao().get(splicingKeySafe(tokenValue, service));
+ return !(SaFoxUtil.isEmpty(value));
+ }
+
+ /**
+ * 校验:当前会话是否已通过二级认证,如未通过则抛出异常
+ */
+ public void checkSafe() {
+ checkSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
+ }
+
+ /**
+ * 校验:检查当前会话是否已通过指定业务的二级认证,如未通过则抛出异常
+ *
+ * @param service 业务标识
+ */
+ public void checkSafe(String service) {
+ // 1、必须先通过登录校验
+ checkLogin();
+
+ // 2、再进行二级认证校验
+ // 如果缓存中可以查询出指定的键值,则代表已认证,否则视为未认证
+ String tokenValue = getTokenValue();
+ String value = getSaTokenDao().get(splicingKeySafe(tokenValue, service));
+ if (SaFoxUtil.isEmpty(value)) {
+ throw new NotSafeException(loginType, tokenValue, service).setCode(SaErrorCode.CODE_11071);
+ }
+ }
+
+ /**
+ * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
+ *
+ * @return 剩余有效时间
+ */
+ public long getSafeTime() {
+ return getSafeTime(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
+ }
+
+ /**
+ * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
+ *
+ * @param service 业务标识
+ * @return 剩余有效时间
+ */
+ public long getSafeTime(String service) {
+ // 1、如果前端没有提交 Token,则直接视为未认证
+ String tokenValue = getTokenValue();
+ if (SaFoxUtil.isEmpty(tokenValue)) {
+ return SaTokenDao.NOT_VALUE_EXPIRE;
+ }
+
+ // 2、从缓存中查询这个 key 的剩余有效期
+ return getSaTokenDao().getTimeout(splicingKeySafe(tokenValue, service));
+ }
+
+ /**
+ * 在当前会话 结束二级认证
+ */
+ public void closeSafe() {
+ closeSafe(SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE);
+ }
+
+ /**
+ * 在当前会话 结束指定业务标识的二级认证
+ *
+ * @param service 业务标识
+ */
+ public void closeSafe(String service) {
+ // 1、如果前端没有提交 Token,则无需任何操作
+ String tokenValue = getTokenValue();
+ if (SaFoxUtil.isEmpty(tokenValue)) {
+ return;
+ }
+
+ // 2、删除 key
+ getSaTokenDao().delete(splicingKeySafe(tokenValue, service));
+
+ // 3、$$ 发布事件,某某 token 令牌关闭了二级认证
+ SaTokenEventCenter.doCloseSafe(loginType, tokenValue, service);
+ }
+
+
+ // ------------------- 拼接相应key -------------------
+
+ /**
+ * 获取:客户端 tokenName
+ *
+ * @return key
+ */
+ public String splicingKeyTokenName() {
+ return getConfigOrGlobal().getTokenName();
+ }
+
+ /**
+ * 拼接: 在保存 token - id 映射关系时,应该使用的key
+ *
+ * @param tokenValue token值
+ * @return key
+ */
+ public String splicingKeyTokenValue(String tokenValue) {
+ return getConfigOrGlobal().getTokenName() + ":" + loginType + ":token:" + tokenValue;
+ }
+
+ /**
+ * 拼接: 在保存 Account-Session 时,应该使用的 key
+ *
+ * @param loginId 账号id
+ * @return key
+ */
+ public String splicingKeySession(Object loginId) {
+ return getConfigOrGlobal().getTokenName() + ":" + loginType + ":session:" + loginId;
+ }
+
+ /**
+ * 拼接:在保存 Token-Session 时,应该使用的 key
+ *
+ * @param tokenValue token值
+ * @return key
+ */
+ public String splicingKeyTokenSession(String tokenValue) {
+ return getConfigOrGlobal().getTokenName() + ":" + loginType + ":token-session:" + tokenValue;
+ }
+
+ /**
+ * 拼接: 在保存 token 最后活跃时间时,应该使用的 key
+ *
+ * @param tokenValue token值
+ * @return key
+ */
+ public String splicingKeyLastActiveTime(String tokenValue) {
+ return getConfigOrGlobal().getTokenName() + ":" + loginType + ":last-active:" + tokenValue;
+ }
+
+ /**
+ * 拼接:在进行临时身份切换时,应该使用的 key
+ *
+ * @return key
+ */
+ public String splicingKeySwitch() {
+ return SaTokenConsts.SWITCH_TO_SAVE_KEY + loginType;
+ }
+
+ /**
+ * 如果 token 为本次请求新创建的,则以此字符串为 key 存储在当前 request 中
+ *
+ * @return key
+ */
+ public String splicingKeyJustCreatedSave() {
// return SaTokenConsts.JUST_CREATED_SAVE_KEY + loginType;
- return SaTokenConsts.JUST_CREATED;
- }
-
- /**
- * 拼接: 在保存服务封禁标记时,应该使用的 key
- *
- * @param loginId 账号id
- * @param service 具体封禁的服务
- * @return key
- */
- public String splicingKeyDisable(Object loginId, String service) {
- return getConfigOrGlobal().getTokenName() + ":" + loginType + ":disable:" + service + ":" + loginId;
- }
-
- /**
- * 拼接: 在保存业务二级认证标记时,应该使用的 key
- *
- * @param tokenValue 要认证的 Token
- * @param service 要认证的业务标识
- * @return key
- */
- public String splicingKeySafe(String tokenValue, String service) {
- // 格式: 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4
- * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token,
- * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId
- *
- * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token,
- * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId
- * 此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
- *
- * @param loginId 指定账号id
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public static void disable(Object loginId, long time) {
- stpLogic.disable(loginId, time);
- }
-
- /**
- * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
- *
- * @param loginId 账号id
- * @return /
- */
- public static boolean isDisable(Object loginId) {
- return stpLogic.isDisable(loginId);
- }
-
- /**
- * 校验:指定账号是否已被封禁,如果被封禁则抛出异常
- *
- * @param loginId 账号id
- */
- public static void checkDisable(Object loginId) {
- stpLogic.checkDisable(loginId);
- }
-
- /**
- * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
- *
- * @param loginId 账号id
- * @return /
- */
- public static long getDisableTime(Object loginId) {
- return stpLogic.getDisableTime(loginId);
- }
-
- /**
- * 解封:指定账号
- *
- * @param loginId 账号id
- */
- public static void untieDisable(Object loginId) {
- stpLogic.untieDisable(loginId);
- }
-
-
- // ------------------- 分类封禁 -------------------
-
- /**
- * 封禁:指定账号的指定服务
- * 此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
- *
- * @param loginId 指定账号id
- * @param service 指定服务
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public static void disable(Object loginId, String service, long time) {
- stpLogic.disable(loginId, service, time);
- }
-
- /**
- * 判断:指定账号的指定服务 是否已被封禁(true=已被封禁, false=未被封禁)
- *
- * @param loginId 账号id
- * @param service 指定服务
- * @return /
- */
- public static boolean isDisable(Object loginId, String service) {
- return stpLogic.isDisable(loginId, service);
- }
-
- /**
- * 校验:指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常
- *
- * @param loginId 账号id
- * @param services 指定服务,可以指定多个
- */
- public static void checkDisable(Object loginId, String... services) {
- stpLogic.checkDisable(loginId, services);
- }
-
- /**
- * 获取:指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
- *
- * @param loginId 账号id
- * @param service 指定服务
- * @return see note
- */
- public static long getDisableTime(Object loginId, String service) {
- return stpLogic.getDisableTime(loginId, service);
- }
-
- /**
- * 解封:指定账号、指定服务
- *
- * @param loginId 账号id
- * @param services 指定服务,可以指定多个
- */
- public static void untieDisable(Object loginId, String... services) {
- stpLogic.untieDisable(loginId, services);
- }
-
-
- // ------------------- 阶梯封禁 -------------------
-
- /**
- * 封禁:指定账号,并指定封禁等级
- *
- * @param loginId 指定账号id
- * @param level 指定封禁等级
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public static void disableLevel(Object loginId, int level, long time) {
- stpLogic.disableLevel(loginId, level, time);
- }
-
- /**
- * 封禁:指定账号的指定服务,并指定封禁等级
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @param level 指定封禁等级
- * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
- */
- public static void disableLevel(Object loginId, String service, int level, long time) {
- stpLogic.disableLevel(loginId, service, level, time);
- }
-
- /**
- * 判断:指定账号是否已被封禁到指定等级
- *
- * @param loginId 指定账号id
- * @param level 指定封禁等级
- * @return /
- */
- public static boolean isDisableLevel(Object loginId, int level) {
- return stpLogic.isDisableLevel(loginId, level);
- }
-
- /**
- * 判断:指定账号的指定服务,是否已被封禁到指定等级
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @param level 指定封禁等级
- * @return /
- */
- public static boolean isDisableLevel(Object loginId, String service, int level) {
- return stpLogic.isDisableLevel(loginId, service, level);
- }
-
- /**
- * 校验:指定账号是否已被封禁到指定等级(如果已经达到,则抛出异常)
- *
- * @param loginId 指定账号id
- * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
- */
- public static void checkDisableLevel(Object loginId, int level) {
- stpLogic.checkDisableLevel(loginId, level);
- }
-
- /**
- * 校验:指定账号的指定服务,是否已被封禁到指定等级(如果已经达到,则抛出异常)
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
- */
- public static void checkDisableLevel(Object loginId, String service, int level) {
- stpLogic.checkDisableLevel(loginId, service, level);
- }
-
- /**
- * 获取:指定账号被封禁的等级,如果未被封禁则返回-2
- *
- * @param loginId 指定账号id
- * @return /
- */
- public static int getDisableLevel(Object loginId) {
- return stpLogic.getDisableLevel(loginId);
- }
-
- /**
- * 获取:指定账号的 指定服务 被封禁的等级,如果未被封禁则返回-2
- *
- * @param loginId 指定账号id
- * @param service 指定封禁服务
- * @return /
- */
- public static int getDisableLevel(Object loginId, String service) {
- return stpLogic.getDisableLevel(loginId, service);
- }
-
-
- // ------------------- 临时身份切换 -------------------
-
- /**
- * 临时切换身份为指定账号id
- *
- * @param loginId 指定loginId
- */
- public static void switchTo(Object loginId) {
- stpLogic.switchTo(loginId);
- }
-
- /**
- * 结束临时切换身份
- */
- public static void endSwitch() {
- stpLogic.endSwitch();
- }
-
- /**
- * 判断当前请求是否正处于 [ 身份临时切换 ] 中
- *
- * @return /
- */
- public static boolean isSwitch() {
- return stpLogic.isSwitch();
- }
-
- /**
- * 在一个 lambda 代码段里,临时切换身份为指定账号id,lambda 结束后自动恢复
- *
- * @param loginId 指定账号id
- * @param function 要执行的方法
- */
- public static void switchTo(Object loginId, SaFunction function) {
- stpLogic.switchTo(loginId, function);
- }
-
-
- // ------------------- 二级认证 -------------------
-
- /**
- * 在当前会话 开启二级认证
- *
- * @param safeTime 维持时间 (单位: 秒)
- */
- public static void openSafe(long safeTime) {
- stpLogic.openSafe(safeTime);
- }
-
- /**
- * 在当前会话 开启二级认证
- *
- * @param service 业务标识
- * @param safeTime 维持时间 (单位: 秒)
- */
- public static void openSafe(String service, long safeTime) {
- stpLogic.openSafe(service, safeTime);
- }
-
- /**
- * 判断:当前会话是否处于二级认证时间内
- *
- * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
- */
- public static boolean isSafe() {
- return stpLogic.isSafe();
- }
-
- /**
- * 判断:当前会话 是否处于指定业务的二级认证时间内
- *
- * @param service 业务标识
- * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
- */
- public static boolean isSafe(String service) {
- return stpLogic.isSafe(service);
- }
-
- /**
- * 判断:指定 token 是否处于二级认证时间内
- *
- * @param tokenValue Token 值
- * @param service 业务标识
- * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
- */
- public static boolean isSafe(String tokenValue, String service) {
- return stpLogic.isSafe(tokenValue, service);
- }
-
- /**
- * 校验:当前会话是否已通过二级认证,如未通过则抛出异常
- */
- public static void checkSafe() {
- stpLogic.checkSafe();
- }
-
- /**
- * 校验:检查当前会话是否已通过指定业务的二级认证,如未通过则抛出异常
- *
- * @param service 业务标识
- */
- public static void checkSafe(String service) {
- stpLogic.checkSafe(service);
- }
-
- /**
- * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
- *
- * @return 剩余有效时间
- */
- public static long getSafeTime() {
- return stpLogic.getSafeTime();
- }
-
- /**
- * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
- *
- * @param service 业务标识
- * @return 剩余有效时间
- */
- public static long getSafeTime(String service) {
- return stpLogic.getSafeTime(service);
- }
-
- /**
- * 在当前会话 结束二级认证
- */
- public static void closeSafe() {
- stpLogic.closeSafe();
- }
-
- /**
- * 在当前会话 结束指定业务标识的二级认证
- *
- * @param service 业务标识
- */
- public static void closeSafe(String service) {
- stpLogic.closeSafe(service);
- }
+
+ private StpUtil() {
+ }
+
+ /**
+ * 多账号体系下的类型标识
+ */
+ public static final String TYPE = "login";
+
+ /**
+ * 底层使用的 StpLogic 对象
+ */
+ public static StpLogic stpLogic = new StpLogic(TYPE);
+
+ /**
+ * 获取当前 StpLogic 的账号类型
+ *
+ * @return /
+ */
+ public static String getLoginType() {
+ return stpLogic.getLoginType();
+ }
+
+ /**
+ * 安全的重置 StpLogic 对象
+ *
+ *
+ * 使用场景 在调用 {@link StpUtil#login(Object, String)} 时 倘如传参为login,Android-XiaoMi 14
+ * 那么可以使用此方法来批量获取设备登录信息 来给前端进行设备token管理
+ *
+ * @return 当前账号登录信息列表
+ */
+ public static List 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-5 当对方再次访问系统时,会抛出 NotLoginException 异常,场景值=-4
+ * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token,
+ * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId
+ *
+ * 在配置为允许并发登录时,此方法只会返回队列的最后一个 token,
+ * 如果你需要返回此账号 id 的所有 token,请调用 getTokenValueListByLoginId
+ * 此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
+ *
+ * @param loginId 指定账号id
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public static void disable(Object loginId, long time) {
+ stpLogic.disable(loginId, time);
+ }
+
+ /**
+ * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
+ *
+ * @param loginId 账号id
+ * @return /
+ */
+ public static boolean isDisable(Object loginId) {
+ return stpLogic.isDisable(loginId);
+ }
+
+ /**
+ * 校验:指定账号是否已被封禁,如果被封禁则抛出异常
+ *
+ * @param loginId 账号id
+ */
+ public static void checkDisable(Object loginId) {
+ stpLogic.checkDisable(loginId);
+ }
+
+ /**
+ * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
+ *
+ * @param loginId 账号id
+ * @return /
+ */
+ public static long getDisableTime(Object loginId) {
+ return stpLogic.getDisableTime(loginId);
+ }
+
+ /**
+ * 解封:指定账号
+ *
+ * @param loginId 账号id
+ */
+ public static void untieDisable(Object loginId) {
+ stpLogic.untieDisable(loginId);
+ }
+
+
+ // ------------------- 分类封禁 -------------------
+
+ /**
+ * 封禁:指定账号的指定服务
+ * 此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id)
+ *
+ * @param loginId 指定账号id
+ * @param service 指定服务
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public static void disable(Object loginId, String service, long time) {
+ stpLogic.disable(loginId, service, time);
+ }
+
+ /**
+ * 判断:指定账号的指定服务 是否已被封禁(true=已被封禁, false=未被封禁)
+ *
+ * @param loginId 账号id
+ * @param service 指定服务
+ * @return /
+ */
+ public static boolean isDisable(Object loginId, String service) {
+ return stpLogic.isDisable(loginId, service);
+ }
+
+ /**
+ * 校验:指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常
+ *
+ * @param loginId 账号id
+ * @param services 指定服务,可以指定多个
+ */
+ public static void checkDisable(Object loginId, String... services) {
+ stpLogic.checkDisable(loginId, services);
+ }
+
+ /**
+ * 获取:指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
+ *
+ * @param loginId 账号id
+ * @param service 指定服务
+ * @return see note
+ */
+ public static long getDisableTime(Object loginId, String service) {
+ return stpLogic.getDisableTime(loginId, service);
+ }
+
+ /**
+ * 解封:指定账号、指定服务
+ *
+ * @param loginId 账号id
+ * @param services 指定服务,可以指定多个
+ */
+ public static void untieDisable(Object loginId, String... services) {
+ stpLogic.untieDisable(loginId, services);
+ }
+
+
+ // ------------------- 阶梯封禁 -------------------
+
+ /**
+ * 封禁:指定账号,并指定封禁等级
+ *
+ * @param loginId 指定账号id
+ * @param level 指定封禁等级
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public static void disableLevel(Object loginId, int level, long time) {
+ stpLogic.disableLevel(loginId, level, time);
+ }
+
+ /**
+ * 封禁:指定账号的指定服务,并指定封禁等级
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @param level 指定封禁等级
+ * @param time 封禁时间, 单位: 秒 (-1=永久封禁)
+ */
+ public static void disableLevel(Object loginId, String service, int level, long time) {
+ stpLogic.disableLevel(loginId, service, level, time);
+ }
+
+ /**
+ * 判断:指定账号是否已被封禁到指定等级
+ *
+ * @param loginId 指定账号id
+ * @param level 指定封禁等级
+ * @return /
+ */
+ public static boolean isDisableLevel(Object loginId, int level) {
+ return stpLogic.isDisableLevel(loginId, level);
+ }
+
+ /**
+ * 判断:指定账号的指定服务,是否已被封禁到指定等级
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @param level 指定封禁等级
+ * @return /
+ */
+ public static boolean isDisableLevel(Object loginId, String service, int level) {
+ return stpLogic.isDisableLevel(loginId, service, level);
+ }
+
+ /**
+ * 校验:指定账号是否已被封禁到指定等级(如果已经达到,则抛出异常)
+ *
+ * @param loginId 指定账号id
+ * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
+ */
+ public static void checkDisableLevel(Object loginId, int level) {
+ stpLogic.checkDisableLevel(loginId, level);
+ }
+
+ /**
+ * 校验:指定账号的指定服务,是否已被封禁到指定等级(如果已经达到,则抛出异常)
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)
+ */
+ public static void checkDisableLevel(Object loginId, String service, int level) {
+ stpLogic.checkDisableLevel(loginId, service, level);
+ }
+
+ /**
+ * 获取:指定账号被封禁的等级,如果未被封禁则返回-2
+ *
+ * @param loginId 指定账号id
+ * @return /
+ */
+ public static int getDisableLevel(Object loginId) {
+ return stpLogic.getDisableLevel(loginId);
+ }
+
+ /**
+ * 获取:指定账号的 指定服务 被封禁的等级,如果未被封禁则返回-2
+ *
+ * @param loginId 指定账号id
+ * @param service 指定封禁服务
+ * @return /
+ */
+ public static int getDisableLevel(Object loginId, String service) {
+ return stpLogic.getDisableLevel(loginId, service);
+ }
+
+
+ // ------------------- 临时身份切换 -------------------
+
+ /**
+ * 临时切换身份为指定账号id
+ *
+ * @param loginId 指定loginId
+ */
+ public static void switchTo(Object loginId) {
+ stpLogic.switchTo(loginId);
+ }
+
+ /**
+ * 结束临时切换身份
+ */
+ public static void endSwitch() {
+ stpLogic.endSwitch();
+ }
+
+ /**
+ * 判断当前请求是否正处于 [ 身份临时切换 ] 中
+ *
+ * @return /
+ */
+ public static boolean isSwitch() {
+ return stpLogic.isSwitch();
+ }
+
+ /**
+ * 在一个 lambda 代码段里,临时切换身份为指定账号id,lambda 结束后自动恢复
+ *
+ * @param loginId 指定账号id
+ * @param function 要执行的方法
+ */
+ public static void switchTo(Object loginId, SaFunction function) {
+ stpLogic.switchTo(loginId, function);
+ }
+
+
+ // ------------------- 二级认证 -------------------
+
+ /**
+ * 在当前会话 开启二级认证
+ *
+ * @param safeTime 维持时间 (单位: 秒)
+ */
+ public static void openSafe(long safeTime) {
+ stpLogic.openSafe(safeTime);
+ }
+
+ /**
+ * 在当前会话 开启二级认证
+ *
+ * @param service 业务标识
+ * @param safeTime 维持时间 (单位: 秒)
+ */
+ public static void openSafe(String service, long safeTime) {
+ stpLogic.openSafe(service, safeTime);
+ }
+
+ /**
+ * 判断:当前会话是否处于二级认证时间内
+ *
+ * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+ */
+ public static boolean isSafe() {
+ return stpLogic.isSafe();
+ }
+
+ /**
+ * 判断:当前会话 是否处于指定业务的二级认证时间内
+ *
+ * @param service 业务标识
+ * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+ */
+ public static boolean isSafe(String service) {
+ return stpLogic.isSafe(service);
+ }
+
+ /**
+ * 判断:指定 token 是否处于二级认证时间内
+ *
+ * @param tokenValue Token 值
+ * @param service 业务标识
+ * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+ */
+ public static boolean isSafe(String tokenValue, String service) {
+ return stpLogic.isSafe(tokenValue, service);
+ }
+
+ /**
+ * 校验:当前会话是否已通过二级认证,如未通过则抛出异常
+ */
+ public static void checkSafe() {
+ stpLogic.checkSafe();
+ }
+
+ /**
+ * 校验:检查当前会话是否已通过指定业务的二级认证,如未通过则抛出异常
+ *
+ * @param service 业务标识
+ */
+ public static void checkSafe(String service) {
+ stpLogic.checkSafe(service);
+ }
+
+ /**
+ * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
+ *
+ * @return 剩余有效时间
+ */
+ public static long getSafeTime() {
+ return stpLogic.getSafeTime();
+ }
+
+ /**
+ * 获取:当前会话的二级认证剩余有效时间(单位: 秒, 返回-2代表尚未通过二级认证)
+ *
+ * @param service 业务标识
+ * @return 剩余有效时间
+ */
+ public static long getSafeTime(String service) {
+ return stpLogic.getSafeTime(service);
+ }
+
+ /**
+ * 在当前会话 结束二级认证
+ */
+ public static void closeSafe() {
+ stpLogic.closeSafe();
+ }
+
+ /**
+ * 在当前会话 结束指定业务标识的二级认证
+ *
+ * @param service 业务标识
+ */
+ public static void closeSafe(String service) {
+ stpLogic.closeSafe(service);
+ }
}
+ * 请注意: 即使 token 已被冻结 也可续签成功,
+ * 如果此场景下需要提示续签失败,可在此之前调用 checkActiveTimeout() 强制检查是否冻结即可
+ *
+ */
+ public void updateLastActiveToNow() {
+ updateLastActiveToNow(getTokenValue());
+ }
+
+ /**
+ * 清除指定 Token 的 [ 最后活跃时间记录 ]
+ *
+ * @param tokenValue 指定 token
+ */
+ protected void clearLastActive(String tokenValue) {
+ getSaTokenDao().delete(splicingKeyLastActiveTime(tokenValue));
+ }
+
+ /**
+ * 检查指定 token 是否已被冻结,如果是则抛出异常
+ *
+ * @param tokenValue 指定 token
+ */
+ public void checkActiveTimeout(String tokenValue) {
+
+ // storage.get(key, () -> {}) 可以避免一次请求多次校验,造成不必要的性能消耗
+ SaStorage storage = SaHolder.getStorage();
+ storage.get(SaTokenConsts.TOKEN_ACTIVE_TIMEOUT_CHECKED_KEY, () -> {
+
+ // 1、获取这个 token 的剩余活跃有效期
+ long activeTimeout = getTokenActiveTimeoutByToken(tokenValue);
+
+ // 2、值为 -1 代表此 token 已经被设置永不冻结,无须继续验证
+ if (activeTimeout == SaTokenDao.NEVER_EXPIRE) {
+ return true;
+ }
+
+ // 3、值为 -2 代表已被冻结,此时需要抛出异常
+ if (activeTimeout == SaTokenDao.NOT_VALUE_EXPIRE) {
+ throw NotLoginException.newInstance(loginType, TOKEN_FREEZE, TOKEN_FREEZE_MESSAGE, tokenValue).setCode(SaErrorCode.CODE_11016);
+ }
+
+ // --- 验证通过
+ return true;
+ });
+ }
+
+ /**
+ * 检查当前 token 是否已被冻结,如果是则抛出异常
+ */
+ public void checkActiveTimeout() {
+ checkActiveTimeout(getTokenValue());
+ }
+
+ /**
+ * 获取指定 token 在缓存中的 activeTimeout 值,如果不存在则返回 null
+ *
+ * @param tokenValue 指定token
+ * @return /
+ */
+ public Long getTokenUseActiveTimeout(String tokenValue) {
+ // 在未启用动态 activeTimeout 功能时,直接返回 null
+ if (!getConfigOrGlobal().getDynamicActiveTimeout()) {
+ return null;
+ }
+
+ // 先取出这个 token 的最后活跃时间值
+ String key = splicingKeyLastActiveTime(tokenValue);
+ String value = getSaTokenDao().get(key);
+
+ // 解析,无值的情况下返回 null
+ SaValue2Box box = new SaValue2Box(value);
+ return box.getValue2AsLong(null);
+ }
+
+ /**
+ * 获取指定 token 在缓存中的 activeTimeout 值,如果不存在则返回全局配置的 activeTimeout 值
+ *
+ * @param tokenValue 指定token
+ * @return /
+ */
+ public long getTokenUseActiveTimeoutOrGlobalConfig(String tokenValue) {
+ Long activeTimeout = getTokenUseActiveTimeout(tokenValue);
+ if (activeTimeout == null) {
+ return getConfigOrGlobal().getActiveTimeout();
+ }
+ return activeTimeout;
+ }
+
+ /**
+ * 获取指定 token 的最后活跃时间(13位时间戳),如果不存在则返回 -2
+ *
+ * @param tokenValue 指定token
+ * @return /
+ */
+ public long getTokenLastActiveTime(String tokenValue) {
+ // 1、如果提供的 token 为 null,则返回 -2
+ if (SaFoxUtil.isEmpty(tokenValue)) {
+ return SaTokenDao.NOT_VALUE_EXPIRE;
+ }
+
+ // 2、获取这个 token 的最后活跃时间,13位时间戳
+ String key = splicingKeyLastActiveTime(tokenValue);
+ String lastActiveTimeString = getSaTokenDao().get(key);
+
+ // 3、查不到,返回-2
+ if (lastActiveTimeString == null) {
+ return SaTokenDao.NOT_VALUE_EXPIRE;
+ }
+
+ // 4、根据逗号切割字符串
+ return new SaValue2Box(lastActiveTimeString).getValue1AsLong();
+ }
+
+ /**
+ * 获取当前 token 的最后活跃时间(13位时间戳),如果不存在则返回 -2
+ *
+ * @return /
+ */
+ public long getTokenLastActiveTime() {
+ return getTokenLastActiveTime(getTokenValue());
+ }
+
+
+ // ------------------- 过期时间相关 -------------------
+
+ /**
+ * 获取当前会话 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @return token剩余有效时间
+ */
+ public long getTokenTimeout() {
+ return getTokenTimeout(getTokenValue());
+ }
+
+ /**
+ * 获取指定 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @param token 指定token
+ * @return token剩余有效时间
+ */
+ public long getTokenTimeout(String token) {
+ return getSaTokenDao().getTimeout(splicingKeyTokenValue(token));
+ }
+
+ /**
+ * 获取指定账号 id 的 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @param loginId 指定loginId
+ * @return token剩余有效时间
+ */
+ public long getTokenTimeoutByLoginId(Object loginId) {
+ return getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValueByLoginId(loginId)));
+ }
+
+ /**
+ * 获取当前登录账号的 Account-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @return token剩余有效时间
+ */
+ public long getSessionTimeout() {
+ return getSessionTimeoutByLoginId(getLoginIdDefaultNull());
+ }
+
+ /**
+ * 获取指定账号 id 的 Account-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @param loginId 指定loginId
+ * @return token剩余有效时间
+ */
+ public long getSessionTimeoutByLoginId(Object loginId) {
+ return getSaTokenDao().getSessionTimeout(splicingKeySession(loginId));
+ }
+
+ /**
+ * 获取当前 token 的 Token-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @return token剩余有效时间
+ */
+ public long getTokenSessionTimeout() {
+ return getTokenSessionTimeoutByTokenValue(getTokenValue());
+ }
+
+ /**
+ * 获取指定 token 的 Token-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @param tokenValue 指定token
+ * @return token 剩余有效时间
+ */
+ public long getTokenSessionTimeoutByTokenValue(String tokenValue) {
+ return getSaTokenDao().getSessionTimeout(splicingKeyTokenSession(tokenValue));
+ }
+
+ /**
+ * 获取当前 token 剩余活跃有效期:当前 token 距离被冻结还剩多少时间(单位: 秒,返回 -1 代表永不冻结,-2 代表没有这个值或 token 已被冻结了)
+ *
+ * @return /
+ */
+ public long getTokenActiveTimeout() {
+ return getTokenActiveTimeoutByToken(getTokenValue());
+ }
+
+ /**
+ * 获取指定 token 剩余活跃有效期:这个 token 距离被冻结还剩多少时间(单位: 秒,返回 -1 代表永不冻结,-2 代表没有这个值或 token 已被冻结了)
+ *
+ * @param tokenValue 指定 token
+ * @return /
+ */
+ public long getTokenActiveTimeoutByToken(String tokenValue) {
+
+ // 如果全局配置了永不冻结, 则返回 -1
+ if (!isOpenCheckActiveTimeout()) {
+ return SaTokenDao.NEVER_EXPIRE;
+ }
+
+ // ------ 开始查询
+
+ // 先获取这个 token 的最后活跃时间,13位时间戳
+ long lastActiveTime = getTokenLastActiveTime(tokenValue);
+ if (lastActiveTime == SaTokenDao.NOT_VALUE_EXPIRE) {
+ return SaTokenDao.NOT_VALUE_EXPIRE;
+ }
+
+ // 实际时间差
+ long timeDiff = (System.currentTimeMillis() - lastActiveTime) / 1000;
+ // 该 token 允许的时间差
+ long allowTimeDiff = getTokenUseActiveTimeoutOrGlobalConfig(tokenValue);
+ if (allowTimeDiff == SaTokenDao.NEVER_EXPIRE) {
+ // 如果允许的时间差为 -1 ,则代表永不冻结,此处需要立即返回 -1 ,无需后续计算
+ return SaTokenDao.NEVER_EXPIRE;
+ }
+
+ // 校验这个时间差是否超过了允许的值
+ // 计算公式为: 允许的最大时间差 - 实际时间差,判断是否 < 0, 如果是则代表已经被冻结 ,返回-2
+ long activeTimeout = allowTimeDiff - timeDiff;
+ if (activeTimeout < 0) {
+ return SaTokenDao.NOT_VALUE_EXPIRE;
+ } else {
+ // 否则代表没冻结,返回剩余有效时间
+ return activeTimeout;
+ }
+ }
+
+ /**
+ * 对当前 token 的 timeout 值进行续期
+ *
+ * @param timeout 要修改成为的有效时间 (单位: 秒)
+ */
+ public void renewTimeout(long timeout) {
+ // 1、续期缓存数据
+ String tokenValue = getTokenValue();
+ renewTimeout(tokenValue, timeout);
+
+ // 2、续期客户端 Cookie 有效期
+ if (getConfigOrGlobal().getIsReadCookie()) {
+ // 如果 timeout = -1,代表永久,但是一般浏览器不支持永久 Cookie,所以此处设置为 int 最大值
+ // 如果 timeout 大于 int 最大值,会造成数据溢出,所以也要将其设置为 int 最大值
+ if (timeout == SaTokenDao.NEVER_EXPIRE || timeout > Integer.MAX_VALUE) {
+ timeout = Integer.MAX_VALUE;
+ }
+ setTokenValueToCookie(tokenValue, (int) timeout);
+ }
+ }
+
+ /**
+ * 对指定 token 的 timeout 值进行续期
+ *
+ * @param tokenValue 指定 token
+ * @param timeout 要修改成为的有效时间 (单位: 秒,填 -1 代表要续为永久有效)
+ */
+ public void renewTimeout(String tokenValue, long timeout) {
+
+ // 1、如果 token 指向的 loginId 为空,或者属于异常项时,不进行任何操作
+ Object loginId = getLoginIdByToken(tokenValue);
+ if (loginId == null) {
+ return;
+ }
+
+ // 2、续期此 token 本身的有效期 (改 ttl)
+ SaTokenDao dao = getSaTokenDao();
+ dao.updateTimeout(splicingKeyTokenValue(tokenValue), timeout);
+
+ // 3、续期此 token 的 Token-Session 有效期
+ SaSession tokenSession = getTokenSessionByToken(tokenValue, false);
+ if (tokenSession != null) {
+ tokenSession.updateTimeout(timeout);
+ }
+
+ // 4、续期此 token 指向的账号的 Account-Session 有效期
+ getSessionByLoginId(loginId).updateMinTimeout(timeout);
+
+ // 5、更新此 token 的最后活跃时间
+ if (isOpenCheckActiveTimeout()) {
+ dao.updateTimeout(splicingKeyLastActiveTime(tokenValue), timeout);
+ }
+
+ // 6、$$ 发布事件:某某 token 被续期了
+ SaTokenEventCenter.doRenewTimeout(tokenValue, loginId, timeout);
+ }
+
+
+ // ------------------- 角色认证操作 -------------------
+
+ /**
+ * 获取:当前账号的角色集合
+ *
+ * @return /
+ */
+ public List
1、更改此账户的 StpLogic 对象
- *
2、put 到全局 StpLogic 集合中
- *
3、发送日志
- *
- * @param newStpLogic /
- */
- public static void setStpLogic(StpLogic newStpLogic) {
- // 1、重置此账户的 StpLogic 对象
- stpLogic = newStpLogic;
-
- // 2、添加到全局 StpLogic 集合中
- // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
- SaManager.putStpLogic(newStpLogic);
-
- // 3、$$ 发布事件:更新了 stpLogic 对象
- SaTokenEventCenter.doSetStpLogic(stpLogic);
- }
-
- /**
- * 获取 StpLogic 对象
- *
- * @return /
- */
- public static StpLogic getStpLogic() {
- return stpLogic;
- }
-
-
- // ------------------- 获取 token 相关 -------------------
-
- /**
- * 返回 token 名称,此名称在以下地方体现:Cookie 保存 token 时的名称、提交 token 时参数的名称、存储 token 时的 key 前缀
- *
- * @return /
- */
- public static String getTokenName() {
- return stpLogic.getTokenName();
- }
-
- /**
- * 在当前会话写入指定 token 值
- *
- * @param tokenValue token 值
- */
- public static void setTokenValue(String tokenValue){
- stpLogic.setTokenValue(tokenValue);
- }
-
- /**
- * 在当前会话写入指定 token 值
- *
- * @param tokenValue token 值
- * @param cookieTimeout Cookie存活时间(秒)
- */
- public static void setTokenValue(String tokenValue, int cookieTimeout){
- stpLogic.setTokenValue(tokenValue, cookieTimeout);
- }
-
- /**
- * 在当前会话写入指定 token 值
- *
- * @param tokenValue token 值
- * @param loginModel 登录参数
- */
- public static void setTokenValue(String tokenValue, SaLoginModel loginModel){
- stpLogic.setTokenValue(tokenValue, loginModel);
- }
-
- /**
- * 获取当前请求的 token 值
- *
- * @return 当前tokenValue
- */
- public static String getTokenValue() {
- return stpLogic.getTokenValue();
- }
-
- /**
- * 获取当前请求的 token 值 (不裁剪前缀)
- *
- * @return /
- */
- public static String getTokenValueNotCut(){
- return stpLogic.getTokenValueNotCut();
- }
-
- /**
- * 获取当前会话的 token 参数信息
- *
- * @return token 参数信息
- */
- public static SaTokenInfo getTokenInfo() {
- return stpLogic.getTokenInfo();
- }
-
-
- // ------------------- 登录相关操作 -------------------
-
- // --- 登录
-
- /**
- * 会话登录
- *
- * @param id 账号id,建议的类型:(long | int | String)
- */
- public static void login(Object id) {
- stpLogic.login(id);
- }
-
- /**
- * 会话登录,并指定登录设备类型
- *
- * @param id 账号id,建议的类型:(long | int | String)
- * @param device 设备类型
- */
- public static void login(Object id, String device) {
- stpLogic.login(id, device);
- }
-
- /**
- * 会话登录,并指定是否 [记住我]
- *
- * @param id 账号id,建议的类型:(long | int | String)
- * @param isLastingCookie 是否为持久Cookie,值为 true 时记住我,值为 false 时关闭浏览器需要重新登录
- */
- public static void login(Object id, boolean isLastingCookie) {
- stpLogic.login(id, isLastingCookie);
- }
-
- /**
- * 会话登录,并指定此次登录 token 的有效期, 单位:秒
- *
- * @param id 账号id,建议的类型:(long | int | String)
- * @param timeout 此次登录 token 的有效期, 单位:秒
- */
- public static void login(Object id, long timeout) {
- stpLogic.login(id, timeout);
- }
-
- /**
- * 会话登录,并指定所有登录参数 Model
- *
- * @param id 账号id,建议的类型:(long | int | String)
- * @param loginModel 此次登录的参数Model
- */
- public static void login(Object id, SaLoginModel loginModel) {
- stpLogic.login(id, loginModel);
- }
-
- /**
- * 创建指定账号 id 的登录会话数据
- *
- * @param id 账号id,建议的类型:(long | int | String)
- * @return 返回会话令牌
- */
- public static String createLoginSession(Object id) {
- return stpLogic.createLoginSession(id);
- }
-
- /**
- * 创建指定账号 id 的登录会话数据
- *
- * @param id 账号id,建议的类型:(long | int | String)
- * @param loginModel 此次登录的参数Model
- * @return 返回会话令牌
- */
- public static String createLoginSession(Object id, SaLoginModel loginModel) {
- return stpLogic.createLoginSession(id, loginModel);
- }
-
- // --- 注销
-
- /**
- * 在当前客户端会话注销
- */
- public static void logout() {
- stpLogic.logout();
- }
-
- /**
- * 会话注销,根据账号id
- *
- * @param loginId 账号id
- */
- public static void logout(Object loginId) {
- stpLogic.logout(loginId);
- }
-
- /**
- * 会话注销,根据账号id 和 设备类型
- *
- * @param loginId 账号id
- * @param device 设备类型 (填 null 代表注销该账号的所有设备类型)
- */
- public static void logout(Object loginId, String device) {
- stpLogic.logout(loginId, device);
- }
-
- /**
- * 会话注销,根据指定 Token
- *
- * @param tokenValue 指定 token
- */
- public static void logoutByTokenValue(String tokenValue) {
- stpLogic.logoutByTokenValue(tokenValue);
- }
-
- /**
- * 踢人下线,根据账号id
- *
- * 请注意: 即使 token 已被冻结 也可续签成功,
- * 如果此场景下需要提示续签失败,可在此之前调用 checkActiveTimeout() 强制检查是否冻结即可
- *
- */
- public static void updateLastActiveToNow() {
- stpLogic.updateLastActiveToNow();
- }
-
- /**
- * 检查当前 token 是否已被冻结,如果是则抛出异常
- */
- public static void checkActiveTimeout() {
- stpLogic.checkActiveTimeout();
- }
-
-
- // ------------------- 过期时间相关 -------------------
-
- /**
- * 获取当前会话 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
- *
- * @return token剩余有效时间
- */
- public static long getTokenTimeout() {
- return stpLogic.getTokenTimeout();
- }
-
- /**
- * 获取指定 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
- *
- * @param token 指定token
- * @return token剩余有效时间
- */
- public static long getTokenTimeout(String token) {
- return stpLogic.getTokenTimeout(token);
- }
-
- /**
- * 获取当前登录账号的 Account-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
- *
- * @return token剩余有效时间
- */
- public static long getSessionTimeout() {
- return stpLogic.getSessionTimeout();
- }
-
- /**
- * 获取当前 token 的 Token-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
- *
- * @return token剩余有效时间
- */
- public static long getTokenSessionTimeout() {
- return stpLogic.getTokenSessionTimeout();
- }
-
- /**
- * 获取当前 token 剩余活跃有效期:当前 token 距离被冻结还剩多少时间(单位: 秒,返回 -1 代表永不冻结,-2 代表没有这个值或 token 已被冻结了)
- *
- * @return /
- */
- public static long getTokenActiveTimeout() {
- return stpLogic.getTokenActiveTimeout();
- }
-
- /**
- * 对当前 token 的 timeout 值进行续期
- *
- * @param timeout 要修改成为的有效时间 (单位: 秒)
- */
- public static void renewTimeout(long timeout) {
- stpLogic.renewTimeout(timeout);
- }
-
- /**
- * 对指定 token 的 timeout 值进行续期
- *
- * @param tokenValue 指定 token
- * @param timeout 要修改成为的有效时间 (单位: 秒,填 -1 代表要续为永久有效)
- */
- public static void renewTimeout(String tokenValue, long timeout) {
- stpLogic.renewTimeout(tokenValue, timeout);
- }
-
-
- // ------------------- 角色认证操作 -------------------
-
- /**
- * 获取:当前账号的角色集合
- *
- * @return /
- */
- public static List
1、更改此账户的 StpLogic 对象
+ *
2、put 到全局 StpLogic 集合中
+ *
3、发送日志
+ *
+ * @param newStpLogic /
+ */
+ public static void setStpLogic(StpLogic newStpLogic) {
+ // 1、重置此账户的 StpLogic 对象
+ stpLogic = newStpLogic;
+
+ // 2、添加到全局 StpLogic 集合中
+ // 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
+ SaManager.putStpLogic(newStpLogic);
+
+ // 3、$$ 发布事件:更新了 stpLogic 对象
+ SaTokenEventCenter.doSetStpLogic(stpLogic);
+ }
+
+ /**
+ * 获取 StpLogic 对象
+ *
+ * @return /
+ */
+ public static StpLogic getStpLogic() {
+ return stpLogic;
+ }
+
+ // ------------------- 获取 登录信息 相关 -------------------
+ /**
+ * 获取当前账号id登录信息
+ *
+ * 请注意: 即使 token 已被冻结 也可续签成功,
+ * 如果此场景下需要提示续签失败,可在此之前调用 checkActiveTimeout() 强制检查是否冻结即可
+ *
+ */
+ public static void updateLastActiveToNow() {
+ stpLogic.updateLastActiveToNow();
+ }
+
+ /**
+ * 检查当前 token 是否已被冻结,如果是则抛出异常
+ */
+ public static void checkActiveTimeout() {
+ stpLogic.checkActiveTimeout();
+ }
+
+
+ // ------------------- 过期时间相关 -------------------
+
+ /**
+ * 获取当前会话 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @return token剩余有效时间
+ */
+ public static long getTokenTimeout() {
+ return stpLogic.getTokenTimeout();
+ }
+
+ /**
+ * 获取指定 token 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @param token 指定token
+ * @return token剩余有效时间
+ */
+ public static long getTokenTimeout(String token) {
+ return stpLogic.getTokenTimeout(token);
+ }
+
+ /**
+ * 获取当前登录账号的 Account-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @return token剩余有效时间
+ */
+ public static long getSessionTimeout() {
+ return stpLogic.getSessionTimeout();
+ }
+
+ /**
+ * 获取当前 token 的 Token-Session 剩余有效时间(单位: 秒,返回 -1 代表永久有效,-2 代表没有这个值)
+ *
+ * @return token剩余有效时间
+ */
+ public static long getTokenSessionTimeout() {
+ return stpLogic.getTokenSessionTimeout();
+ }
+
+ /**
+ * 获取当前 token 剩余活跃有效期:当前 token 距离被冻结还剩多少时间(单位: 秒,返回 -1 代表永不冻结,-2 代表没有这个值或 token 已被冻结了)
+ *
+ * @return /
+ */
+ public static long getTokenActiveTimeout() {
+ return stpLogic.getTokenActiveTimeout();
+ }
+
+ /**
+ * 对当前 token 的 timeout 值进行续期
+ *
+ * @param timeout 要修改成为的有效时间 (单位: 秒)
+ */
+ public static void renewTimeout(long timeout) {
+ stpLogic.renewTimeout(timeout);
+ }
+
+ /**
+ * 对指定 token 的 timeout 值进行续期
+ *
+ * @param tokenValue 指定 token
+ * @param timeout 要修改成为的有效时间 (单位: 秒,填 -1 代表要续为永久有效)
+ */
+ public static void renewTimeout(String tokenValue, long timeout) {
+ stpLogic.renewTimeout(tokenValue, timeout);
+ }
+
+
+ // ------------------- 角色认证操作 -------------------
+
+ /**
+ * 获取:当前账号的角色集合
+ *
+ * @return /
+ */
+ public static List