From cb31c61efdbec57ef34ac49001c706c4223ceee7 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 8 Sep 2022 10:16:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=98=B6=E6=A2=AF=E5=B0=81?= =?UTF-8?q?=E7=A6=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/annotation/SaCheckDisable.java | 7 + .../exception/DisableServiceException.java | 57 +++- .../satoken/listener/SaTokenEventCenter.java | 5 +- .../satoken/listener/SaTokenListener.java | 3 +- .../SaTokenListenerForConsolePrint.java | 4 +- .../listener/SaTokenListenerForSimple.java | 2 +- .../java/cn/dev33/satoken/stp/StpLogic.java | 262 +++++++++++++----- .../java/cn/dev33/satoken/stp/StpUtil.java | 215 ++++++++++---- .../cn/dev33/satoken/util/SaTokenConsts.java | 15 + .../java/com/pj/current/GlobalException.java | 2 +- .../java/com/pj/satoken/at/StpUserUtil.java | 215 ++++++++++---- .../java/com/pj/satoken/at/StpUserUtil.java | 215 ++++++++++---- sa-token-doc/doc/_sidebar.md | 4 +- sa-token-doc/doc/up/disable.md | 105 ++++++- sa-token-doc/doc/up/global-listener.md | 2 +- .../java/com/pj/test/JwtForMixinTest.java | 2 +- .../dev33/satoken/springboot/BasicsTest.java | 77 ++++- 17 files changed, 903 insertions(+), 289 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckDisable.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckDisable.java index dfd17858..4f99da9d 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckDisable.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckDisable.java @@ -30,5 +30,12 @@ public @interface SaCheckDisable { * @return see note */ String[] value() default { SaTokenConsts.DEFAULT_DISABLE_SERVICE }; + + /** + * 封禁等级(只有 封禁等级 ≥ 此值 才会抛出异常) + * + * @return / + */ + int level() default SaTokenConsts.DEFAULT_DISABLE_LEVEL; } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/exception/DisableServiceException.java b/sa-token-core/src/main/java/cn/dev33/satoken/exception/DisableServiceException.java index e0de0a14..535f033c 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/exception/DisableServiceException.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/exception/DisableServiceException.java @@ -12,7 +12,8 @@ public class DisableServiceException extends SaTokenException { */ private static final long serialVersionUID = 6806129545290130143L; - /** 异常标记值 */ + /** 异常标记值(已更改为 SaTokenConsts.DEFAULT_DISABLE_LEVEL) */ + @Deprecated public static final String BE_VALUE = "disable"; /** 异常提示语 */ @@ -27,11 +28,6 @@ public class DisableServiceException extends SaTokenException { * 被封禁的账号id */ private Object loginId; - - /** - * 封禁剩余时间,单位:秒 - */ - private long disableTime; /** * 具体被封禁的服务 @@ -39,9 +35,24 @@ public class DisableServiceException extends SaTokenException { private String service; /** - * 获取账号类型 + * 具体被封禁的等级 + */ + private int level; + + /** + * 校验时要求低于的等级 + */ + private int limitLevel; + + /** + * 封禁剩余时间,单位:秒 + */ + private long disableTime; + + /** + * 获取:账号类型 * - * @return See Note + * @return / */ public String getLoginType() { return loginType; @@ -50,7 +61,7 @@ public class DisableServiceException extends SaTokenException { /** * 获取: 被封禁的账号id * - * @return See above + * @return / */ public Object getLoginId() { return loginId; @@ -59,15 +70,33 @@ public class DisableServiceException extends SaTokenException { /** * 获取: 被封禁的服务 * - * @return See above + * @return / */ public Object getService() { return service; } + + /** + * 获取: 被封禁的等级 + * + * @return / + */ + public int getLevel() { + return level; + } + + /** + * 获取: 校验时要求低于的等级 + * + * @return / + */ + public int getLimitLevel() { + return limitLevel; + } /** * 获取: 封禁剩余时间,单位:秒 - * @return See above + * @return / */ public long getDisableTime() { return disableTime; @@ -79,13 +108,17 @@ public class DisableServiceException extends SaTokenException { * @param loginType 账号类型 * @param loginId 被封禁的账号id * @param service 具体封禁的服务 + * @param level 被封禁的等级 + * @param limitLevel 校验时要求低于的等级 * @param disableTime 封禁剩余时间,单位:秒 */ - public DisableServiceException(String loginType, Object loginId, String service, long disableTime) { + public DisableServiceException(String loginType, Object loginId, String service, int level, int limitLevel, long disableTime) { super(BE_MESSAGE + service); this.loginId = loginId; this.loginType = loginType; this.service = service; + this.level = level; + this.limitLevel = limitLevel; this.disableTime = disableTime; } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java index 849d190a..da4906bf 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java @@ -177,11 +177,12 @@ public class SaTokenEventCenter { * @param loginType 账号类别 * @param loginId 账号id * @param service 指定服务 + * @param level 封禁等级 * @param disableTime 封禁时长,单位: 秒 */ - public static void doDisable(String loginType, Object loginId, String service, long disableTime) { + public static void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { for (SaTokenListener listener : listenerList) { - listener.doDisable(loginType, loginId, service, disableTime); + listener.doDisable(loginType, loginId, service, level, disableTime); } } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java index 67bec325..1ef18fe7 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java @@ -48,9 +48,10 @@ public interface SaTokenListener { * @param loginType 账号类别 * @param loginId 账号id * @param service 指定服务 + * @param level 封禁等级 * @param disableTime 封禁时长,单位: 秒 */ - public void doDisable(String loginType, Object loginId, String service, long disableTime); + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime); /** * 每次被解封时触发 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java index 8767edd2..fc52dac8 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java @@ -49,9 +49,9 @@ public class SaTokenListenerForConsolePrint implements SaTokenListener { * 每次被封禁时触发 */ @Override - public void doDisable(String loginType, Object loginId, String service, long disableTime) { + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { Date date = new Date(System.currentTimeMillis() + disableTime * 1000); - println("账号[" + loginId + "] " + service + " 服务被封禁 (解封时间: " + SaFoxUtil.formatDate(date) + ")"); + println("账号[" + loginId + "] " + service + " 服务被封禁,封禁等级=" + level + " (解封时间: " + SaFoxUtil.formatDate(date) + ")"); } /** diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java index 87c18d84..78eba257 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForSimple.java @@ -33,7 +33,7 @@ public class SaTokenListenerForSimple implements SaTokenListener { } @Override - public void doDisable(String loginType, Object loginId, String service, long disableTime) { + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { } 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 abe27c50..e8e1a625 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 @@ -1654,102 +1654,105 @@ public class StpLogic { } /** - * 根据注解(@SaCheckEnable)鉴权 + * 根据注解(@SaCheckDisable)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(SaCheckDisable at) { - this.checkDisable(getLoginId(), at.value()); + Object loginId = getLoginId(); + for (String service : at.value()) { + this.checkDisableLevel(loginId, service, at.level()); + } } + // ------------------- 账号封禁 ------------------- /** - * 封禁指定账号 + * 封禁:指定账号 *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) + * * @param loginId 指定账号id - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) + * @param time 封禁时间, 单位: 秒 (-1=永久封禁) */ - public void disable(Object loginId, long disableTime) { - disable(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, disableTime); + public void disable(Object loginId, long time) { + disableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.DEFAULT_DISABLE_LEVEL, time); } /** - * 封禁 指定账号 指定服务 - *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) - * @param loginId 指定账号id - * @param service 指定服务 - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) - */ - public void disable(Object loginId, String service, long disableTime) { - // 空值检查 - if(SaFoxUtil.isEmpty(loginId)) { - throw new SaTokenException("请提供要封禁的账号"); - } - if(SaFoxUtil.isEmpty(service)) { - throw new SaTokenException("请提供要封禁的服务"); - } - - // 标注为已被封禁 - getSaTokenDao().set(splicingKeyDisable(loginId, service), DisableServiceException.BE_VALUE, disableTime); - - // $$ 发布事件 - SaTokenEventCenter.doDisable(loginType, loginId, service, disableTime); - } - - /** - * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * * @param loginId 账号id - * @return see note + * @return / */ public boolean isDisable(Object loginId) { - return isDisable(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE); + return isDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.MIN_DISABLE_LEVEL); } /** - * 指定账号 指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) - * @param loginId 账号id - * @param service 指定服务 - * @return see note - */ - public boolean isDisable(Object loginId, String service) { - return getSaTokenDao().get(splicingKeyDisable(loginId, service)) != null; - } - - /** - * 校验指定账号是否已被封禁,如果被封禁则抛出异常 + * 校验:指定账号是否已被封禁,如果被封禁则抛出异常 * @param loginId 账号id */ public void checkDisable(Object loginId) { - checkDisable(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE); + checkDisableLevel(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE, SaTokenConsts.MIN_DISABLE_LEVEL); } /** - * 校验 指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常 + * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) * @param loginId 账号id - * @param services 指定服务,可以指定多个 - */ - public void checkDisable(Object loginId, String... services) { - if(services != null) { - for (String service : services) { - if(isDisable(loginId, service)) { - throw new DisableServiceException(loginType, loginId, service, getDisableTime(loginId, service)); - } - } - } - } - - /** - * 获取 指定账号 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) - * @param loginId 账号id - * @return see note + * @return / */ public long getDisableTime(Object loginId) { return getDisableTime(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE); } /** - * 获取 指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) + * 解封:指定账号 + * @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 @@ -1759,15 +1762,7 @@ public class StpLogic { } /** - * 解封指定账号 - * @param loginId 账号id - */ - public void untieDisable(Object loginId) { - untieDisable(loginId, SaTokenConsts.DEFAULT_DISABLE_SERVICE); - } - - /** - * 解封指定账号、指定服务 + * 解封:指定账号、指定服务 * @param loginId 账号id * @param services 指定服务,可以指定多个 */ @@ -1788,7 +1783,132 @@ public class StpLogic { 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("请提供要封禁的账号"); + } + if(SaFoxUtil.isEmpty(service)) { + throw new SaTokenException("请提供要封禁的服务"); + } + if(level < SaTokenConsts.MIN_DISABLE_LEVEL) { + throw new SaTokenException("封禁等级不可以小于最小值:" + SaTokenConsts.MIN_DISABLE_LEVEL); + } + + // 标注为已被封禁 + 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) { + // s1. 检查是否被封禁 + int disableLevel = getDisableLevel(loginId, service); + if(disableLevel == SaTokenConsts.NOT_DISABLE_LEVEL) { + return false; + } + // s2. 检测被封禁的等级是否达到指定级别 + 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) { + // s1. 检查是否被封禁 + String value = getSaTokenDao().get(splicingKeyDisable(loginId, service)); + if(SaFoxUtil.isEmpty(value)) { + return; + } + // s2. 检测被封禁的等级是否达到指定级别 + Integer disableLevel = SaFoxUtil.getValueByType(value, int.class); + if(disableLevel >= level) { + throw new DisableServiceException(loginType, loginId, service, disableLevel, level, getDisableTime(loginId, service)); + } + } + + /** + * 获取:指定账号被封禁的等级,如果未被封禁则返回-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) { + // q1. 如果尚未被封禁,则返回-2 + String value = getSaTokenDao().get(splicingKeyDisable(loginId, service)); + if(SaFoxUtil.isEmpty(value)) { + return SaTokenConsts.NOT_DISABLE_LEVEL; + } + // q2. 转为 int 类型 + return SaFoxUtil.getValueByType(value, int.class); + } + // ------------------- 身份切换 ------------------- diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index a886f138..60d02e10 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -57,7 +57,7 @@ public class StpUtil { } - // =================== 获取token 相关 =================== + // ------------------- 获取token 相关 ------------------- /** * 返回token名称 @@ -109,7 +109,7 @@ public class StpUtil { } - // =================== 登录相关操作 =================== + // ------------------- 登录相关操作 ------------------- // --- 登录 @@ -354,7 +354,7 @@ public class StpUtil { } - // =================== User-Session 相关 =================== + // ------------------- User-Session 相关 ------------------- /** * 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回 @@ -402,7 +402,7 @@ public class StpUtil { } - // =================== Token-Session 相关 =================== + // ------------------- Token-Session 相关 ------------------- /** * 获取指定Token-Session,如果Session尚未创建,则新建并返回 @@ -430,7 +430,7 @@ public class StpUtil { } - // =================== [临时有效期] 验证相关 =================== + // ------------------- [临时有效期] 验证相关 ------------------- /** * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 @@ -449,7 +449,7 @@ public class StpUtil { } - // =================== 过期时间相关 =================== + // ------------------- 过期时间相关 ------------------- /** * 获取当前登录者的 token 剩余有效时间 (单位: 秒) @@ -500,7 +500,8 @@ public class StpUtil { stpLogic.renewTimeout(tokenValue, timeout); } - // =================== 角色验证操作 =================== + + // ------------------- 角色验证操作 ------------------- /** * 获取:当前账号的角色集合 @@ -581,7 +582,7 @@ public class StpUtil { } - // =================== 权限验证操作 =================== + // ------------------- 权限验证操作 ------------------- /** * 获取:当前账号的权限码集合 @@ -662,7 +663,7 @@ public class StpUtil { } - // =================== id 反查token 相关操作 =================== + // ------------------- id 反查token 相关操作 ------------------- /** * 获取指定账号id的tokenValue @@ -715,7 +716,7 @@ public class StpUtil { } - // =================== 会话管理 =================== + // ------------------- 会话管理 ------------------- /** * 根据条件查询Token @@ -760,47 +761,28 @@ public class StpUtil { // ------------------- 账号封禁 ------------------- /** - * 封禁指定账号 + * 封禁:指定账号 *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) + * * @param loginId 指定账号id - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) + * @param time 封禁时间, 单位: 秒 (-1=永久封禁) */ - public static void disable(Object loginId, long disableTime) { - stpLogic.disable(loginId, disableTime); + public static void disable(Object loginId, long time) { + stpLogic.disable(loginId, time); } /** - * 封禁 指定账号 指定服务 - *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) - * @param loginId 指定账号id - * @param service 指定服务 - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) - */ - public static void disable(Object loginId, String service, long disableTime) { - stpLogic.disable(loginId, service, disableTime); - } - - /** - * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * * @param loginId 账号id - * @return see note + * @return / */ public static boolean isDisable(Object loginId) { return stpLogic.isDisable(loginId); } /** - * 指定账号 指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) - * @param loginId 账号id - * @param service 指定服务 - * @return see note - */ - public static boolean isDisable(Object loginId, String service) { - return stpLogic.isDisable(loginId, service); - } - - /** - * 校验指定账号是否已被封禁,如果被封禁则抛出异常 + * 校验:指定账号是否已被封禁,如果被封禁则抛出异常 * @param loginId 账号id */ public static void checkDisable(Object loginId) { @@ -808,25 +790,57 @@ public class StpUtil { } /** - * 校验 指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常 + * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) * @param loginId 账号id - * @param services 指定服务,可以指定多个 - */ - public static void checkDisable(Object loginId, String... services) { - stpLogic.checkDisable(loginId, services); - } - - /** - * 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) - * @param loginId 账号id - * @return see note + * @return / */ public static long getDisableTime(Object loginId) { return stpLogic.getDisableTime(loginId); } /** - * 获取 指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) + * 解封:指定账号 + * @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 @@ -836,24 +850,105 @@ public class StpUtil { } /** - * 解封指定账号 - * @param loginId 账号id - */ - public static void untieDisable(Object loginId) { - stpLogic.untieDisable(loginId); - } - - /** - * 解封指定账号、指定服务 + * 解封:指定账号、指定服务 * @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 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java index ace904b9..4573735a 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java @@ -58,6 +58,21 @@ public class SaTokenConsts { * 常量key标记: 在封禁账号时,默认封禁的服务类型 */ public static final String DEFAULT_DISABLE_SERVICE = "login"; + + /** + * 常量key标记: 在封禁账号时,默认封禁的等级 + */ + public static final int DEFAULT_DISABLE_LEVEL = 1; + + /** + * 常量key标记: 在封禁账号时,可使用的最小封禁级别 + */ + public static final int MIN_DISABLE_LEVEL = 1; + + /** + * 常量key标记: 账号封禁级别,表示未被封禁 + */ + public static final int NOT_DISABLE_LEVEL = -2; /** * 常量key标记: 在进行临时身份切换时使用的key diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java index cad511d1..7ee67369 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java @@ -44,7 +44,7 @@ public class GlobalException { } else if(e instanceof DisableServiceException) { // 如果是被封禁异常 DisableServiceException ee = (DisableServiceException) e; - aj = AjaxJson.getNotJur("当前账号 " + ee.getService() + " 服务已被封禁:" + ee.getDisableTime() + "秒后解封"); + aj = AjaxJson.getNotJur("当前账号 " + ee.getService() + " 服务已被封禁 (level=" + ee.getLevel() + "):" + ee.getDisableTime() + "秒后解封"); } else { // 普通异常, 输出:500 + 异常信息 aj = AjaxJson.getError(e.getMessage()); diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java index f87e8c8c..30cdc1a9 100644 --- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -60,7 +60,7 @@ public class StpUserUtil { } - // =================== 获取token 相关 =================== + // ------------------- 获取token 相关 ------------------- /** * 返回token名称 @@ -112,7 +112,7 @@ public class StpUserUtil { } - // =================== 登录相关操作 =================== + // ------------------- 登录相关操作 ------------------- // --- 登录 @@ -357,7 +357,7 @@ public class StpUserUtil { } - // =================== User-Session 相关 =================== + // ------------------- User-Session 相关 ------------------- /** * 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回 @@ -405,7 +405,7 @@ public class StpUserUtil { } - // =================== Token-Session 相关 =================== + // ------------------- Token-Session 相关 ------------------- /** * 获取指定Token-Session,如果Session尚未创建,则新建并返回 @@ -433,7 +433,7 @@ public class StpUserUtil { } - // =================== [临时有效期] 验证相关 =================== + // ------------------- [临时有效期] 验证相关 ------------------- /** * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 @@ -452,7 +452,7 @@ public class StpUserUtil { } - // =================== 过期时间相关 =================== + // ------------------- 过期时间相关 ------------------- /** * 获取当前登录者的 token 剩余有效时间 (单位: 秒) @@ -503,7 +503,8 @@ public class StpUserUtil { stpLogic.renewTimeout(tokenValue, timeout); } - // =================== 角色验证操作 =================== + + // ------------------- 角色验证操作 ------------------- /** * 获取:当前账号的角色集合 @@ -584,7 +585,7 @@ public class StpUserUtil { } - // =================== 权限验证操作 =================== + // ------------------- 权限验证操作 ------------------- /** * 获取:当前账号的权限码集合 @@ -665,7 +666,7 @@ public class StpUserUtil { } - // =================== id 反查token 相关操作 =================== + // ------------------- id 反查token 相关操作 ------------------- /** * 获取指定账号id的tokenValue @@ -718,7 +719,7 @@ public class StpUserUtil { } - // =================== 会话管理 =================== + // ------------------- 会话管理 ------------------- /** * 根据条件查询Token @@ -763,47 +764,28 @@ public class StpUserUtil { // ------------------- 账号封禁 ------------------- /** - * 封禁指定账号 + * 封禁:指定账号 *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) + * * @param loginId 指定账号id - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) + * @param time 封禁时间, 单位: 秒 (-1=永久封禁) */ - public static void disable(Object loginId, long disableTime) { - stpLogic.disable(loginId, disableTime); + public static void disable(Object loginId, long time) { + stpLogic.disable(loginId, time); } /** - * 封禁 指定账号 指定服务 - *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) - * @param loginId 指定账号id - * @param service 指定服务 - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) - */ - public static void disable(Object loginId, String service, long disableTime) { - stpLogic.disable(loginId, service, disableTime); - } - - /** - * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * * @param loginId 账号id - * @return see note + * @return / */ public static boolean isDisable(Object loginId) { return stpLogic.isDisable(loginId); } /** - * 指定账号 指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) - * @param loginId 账号id - * @param service 指定服务 - * @return see note - */ - public static boolean isDisable(Object loginId, String service) { - return stpLogic.isDisable(loginId, service); - } - - /** - * 校验指定账号是否已被封禁,如果被封禁则抛出异常 + * 校验:指定账号是否已被封禁,如果被封禁则抛出异常 * @param loginId 账号id */ public static void checkDisable(Object loginId) { @@ -811,25 +793,57 @@ public class StpUserUtil { } /** - * 校验 指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常 + * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) * @param loginId 账号id - * @param services 指定服务,可以指定多个 - */ - public static void checkDisable(Object loginId, String... services) { - stpLogic.checkDisable(loginId, services); - } - - /** - * 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) - * @param loginId 账号id - * @return see note + * @return / */ public static long getDisableTime(Object loginId) { return stpLogic.getDisableTime(loginId); } /** - * 获取 指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) + * 解封:指定账号 + * @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 @@ -839,24 +853,105 @@ public class StpUserUtil { } /** - * 解封指定账号 - * @param loginId 账号id - */ - public static void untieDisable(Object loginId) { - stpLogic.untieDisable(loginId); - } - - /** - * 解封指定账号、指定服务 + * 解封:指定账号、指定服务 * @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 diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java index f87e8c8c..30cdc1a9 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -60,7 +60,7 @@ public class StpUserUtil { } - // =================== 获取token 相关 =================== + // ------------------- 获取token 相关 ------------------- /** * 返回token名称 @@ -112,7 +112,7 @@ public class StpUserUtil { } - // =================== 登录相关操作 =================== + // ------------------- 登录相关操作 ------------------- // --- 登录 @@ -357,7 +357,7 @@ public class StpUserUtil { } - // =================== User-Session 相关 =================== + // ------------------- User-Session 相关 ------------------- /** * 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回 @@ -405,7 +405,7 @@ public class StpUserUtil { } - // =================== Token-Session 相关 =================== + // ------------------- Token-Session 相关 ------------------- /** * 获取指定Token-Session,如果Session尚未创建,则新建并返回 @@ -433,7 +433,7 @@ public class StpUserUtil { } - // =================== [临时有效期] 验证相关 =================== + // ------------------- [临时有效期] 验证相关 ------------------- /** * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 @@ -452,7 +452,7 @@ public class StpUserUtil { } - // =================== 过期时间相关 =================== + // ------------------- 过期时间相关 ------------------- /** * 获取当前登录者的 token 剩余有效时间 (单位: 秒) @@ -503,7 +503,8 @@ public class StpUserUtil { stpLogic.renewTimeout(tokenValue, timeout); } - // =================== 角色验证操作 =================== + + // ------------------- 角色验证操作 ------------------- /** * 获取:当前账号的角色集合 @@ -584,7 +585,7 @@ public class StpUserUtil { } - // =================== 权限验证操作 =================== + // ------------------- 权限验证操作 ------------------- /** * 获取:当前账号的权限码集合 @@ -665,7 +666,7 @@ public class StpUserUtil { } - // =================== id 反查token 相关操作 =================== + // ------------------- id 反查token 相关操作 ------------------- /** * 获取指定账号id的tokenValue @@ -718,7 +719,7 @@ public class StpUserUtil { } - // =================== 会话管理 =================== + // ------------------- 会话管理 ------------------- /** * 根据条件查询Token @@ -763,47 +764,28 @@ public class StpUserUtil { // ------------------- 账号封禁 ------------------- /** - * 封禁指定账号 + * 封禁:指定账号 *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) + * * @param loginId 指定账号id - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) + * @param time 封禁时间, 单位: 秒 (-1=永久封禁) */ - public static void disable(Object loginId, long disableTime) { - stpLogic.disable(loginId, disableTime); + public static void disable(Object loginId, long time) { + stpLogic.disable(loginId, time); } /** - * 封禁 指定账号 指定服务 - *
此方法不会直接将此账号id踢下线,如需封禁后立即掉线,请追加调用 StpUtil.logout(id) - * @param loginId 指定账号id - * @param service 指定服务 - * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) - */ - public static void disable(Object loginId, String service, long disableTime) { - stpLogic.disable(loginId, service, disableTime); - } - - /** - * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * 判断:指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * * @param loginId 账号id - * @return see note + * @return / */ public static boolean isDisable(Object loginId) { return stpLogic.isDisable(loginId); } /** - * 指定账号 指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) - * @param loginId 账号id - * @param service 指定服务 - * @return see note - */ - public static boolean isDisable(Object loginId, String service) { - return stpLogic.isDisable(loginId, service); - } - - /** - * 校验指定账号是否已被封禁,如果被封禁则抛出异常 + * 校验:指定账号是否已被封禁,如果被封禁则抛出异常 * @param loginId 账号id */ public static void checkDisable(Object loginId) { @@ -811,25 +793,57 @@ public class StpUserUtil { } /** - * 校验 指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常 + * 获取:指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) * @param loginId 账号id - * @param services 指定服务,可以指定多个 - */ - public static void checkDisable(Object loginId, String... services) { - stpLogic.checkDisable(loginId, services); - } - - /** - * 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) - * @param loginId 账号id - * @return see note + * @return / */ public static long getDisableTime(Object loginId) { return stpLogic.getDisableTime(loginId); } /** - * 获取 指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) + * 解封:指定账号 + * @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 @@ -839,24 +853,105 @@ public class StpUserUtil { } /** - * 解封指定账号 - * @param loginId 账号id - */ - public static void untieDisable(Object loginId) { - stpLogic.untieDisable(loginId); - } - - /** - * 解封指定账号、指定服务 + * 解封:指定账号、指定服务 * @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 diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index 5629fd79..44199835 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -21,10 +21,10 @@ - [自定义Token风格](/up/token-style) - [自定义Token前缀](/up/token-prefix) - [记住我模式](/up/remember-me) - - [账号封禁](/up/disable) + - [二级认证](/up/safe-auth) - [模拟他人 & 身份切换](/up/mock-person) - [同端互斥登录](/up/mutex-login) - - [二级认证](/up/safe-auth) + - [账号封禁](/up/disable) - [密码加密](/up/password-secure) - [会话治理](/up/search-session) - [Http Basic 认证](/up/basic-auth) diff --git a/sa-token-doc/doc/up/disable.md b/sa-token-doc/doc/up/disable.md index 040f0cbd..8ce84a0f 100644 --- a/sa-token-doc/doc/up/disable.md +++ b/sa-token-doc/doc/up/disable.md @@ -85,7 +85,7 @@ StpUtil.checkDisable(10001, "place-order"); // 现在我们再将其下单能力封禁一下,期限为 7天 StpUtil.disable(10001, "place-order", 86400 * 7); -// 然后在下单接口,我们添加上校验代码,此时用户便为因为下单能力被封禁而无法下单(代码抛出异常) +// 然后在下单接口,我们添加上校验代码,此时用户便会因为下单能力被封禁而无法下单(代码抛出异常) StpUtil.checkDisable(10001, "place-order"); // 但是此时,用户如果调用开店功能的话,还是可以通过,因为我们没有限制其开店能力 (除非我们再调用了封禁开店的代码) @@ -96,26 +96,91 @@ StpUtil.checkDisable(10001, "open-shop"); 有关分类封禁的所有方法: ``` java -// 封禁 指定账号 指定服务 -StpUtil.disable(10001, "comment", 86400); +// 封禁:指定账号的指定服务 +StpUtil.disable(10001, "<业务标识>", 86400); -// 指定账号 指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) -StpUtil.isDisable(10001, "comment"); +// 判断:指定账号的指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) +StpUtil.isDisable(10001, "<业务标识>"); -// 校验 指定账号 指定服务 是否已被封禁,如果被封禁则抛出异常 `DisableServiceException` -StpUtil.checkDisable(10001, "comment"); +// 校验:指定账号的指定服务 是否已被封禁,如果被封禁则抛出异常 `DisableServiceException` +StpUtil.checkDisable(10001, "<业务标识>"); -// 获取 指定账号 指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) -StpUtil.getDisableTime(10001, "comment"); +// 获取:指定账号的指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) +StpUtil.getDisableTime(10001, "<业务标识>"); -// 解封指定账号、指定服务 -StpUtil.untieDisable(10001, "comment"); +// 解封:指定账号的指定服务 +StpUtil.untieDisable(10001, "<业务标识>"); ``` -### 3、使用注解完成封禁校验 + +### 3、阶梯封禁 + +对于多次违规的用户,我们常常采取阶梯处罚的策略,这种 “阶梯” 一般有两种形式: + +- 处罚时间阶梯:首次违规封禁 1 天,第二次封禁 7 天,第三次封禁 30 天,依次顺延…… +- 处罚力度阶梯:首次违规消息提醒、第二次禁言禁评论、第三次禁止账号登录,等等…… + +基于处罚时间的阶梯,我们只需在封禁时 `StpUtil.disable(10001, 86400)` 传入不同的封禁时间即可,下面我们着重探讨一下基于处罚力度的阶梯形式。 + +假设我们在开发一个论坛系统,对于违规账号的处罚,我们设定三种力度: + +- 1、轻度违规:封禁其发帖、评论能力,但允许其点赞、关注等操作。 +- 2、中度违规:封禁其发帖、评论、点赞、关注等一切与别人互动的能力,但允许其浏览帖子、浏览评论。 +- 3、重度违规:封禁其登录功能,限制一切能力。 + +解决这种需求的关键在于,我们需要把不同处罚力度,量化成不同的处罚等级,比如上述的 `轻度`、`中度`、`重度` 3 个力度, +我们将其量化为`一级封禁`、`二级封禁`、`三级封禁` 3个等级,数字越大代表封禁力度越高。 + +然后我们就可以使用阶梯封禁的API,进行鉴权了: + +``` java +// 阶梯封禁,参数:封禁账号、封禁级别、封禁时间 +StpUtil.disableLevel(10001, 3, 10000); + +// 获取:指定账号封禁的级别 (如果此账号未被封禁则返回 -2) +StpUtil.getDisableLevel(10001); + +// 判断:指定账号是否已被封禁到指定级别,返回 true 或 false +StpUtil.isDisableLevel(10001, 3); + +// 校验:指定账号是否已被封禁到指定级别,如果已达到此级别(例如已被3级封禁,这里校验是否达到2级),则抛出异常 `DisableServiceException` +StpUtil.checkDisableLevel(10001, 2); +``` + +注意点:`DisableServiceException` 异常代表当前账号未通过封禁校验,可以: +- 通过 `e.getLevel()` 获取这个账号实际被封禁的等级。 +- 通过 `e.getLimitLevel()` 获取这个账号在校验时要求低于的等级。当 `Level >= LimitLevel` 时,框架就会抛出异常。 + +如果业务足够复杂,我们还可能将 分类封禁 和 阶梯封禁 组合使用: + +``` java +// 分类阶梯封禁,参数:封禁账号、封禁服务、封禁级别、封禁时间 +StpUtil.disableLevel(10001, "comment", 3, 10000); + +// 获取:指定账号的指定服务 封禁的级别 (如果此账号未被封禁则返回 -2) +StpUtil.getDisableLevel(10001, "comment"); + +// 判断:指定账号的指定服务 是否已被封禁到指定级别,返回 true 或 false +StpUtil.isDisableLevel(10001, "comment", 3); + +// 校验:指定账号的指定服务 是否已被封禁到指定级别(例如 comment服务 已被3级封禁,这里校验是否达到2级),如果已达到此级别,则抛出异常 +StpUtil.checkDisableLevel(10001, "comment", 2); +``` + + + +### 4、使用注解完成封禁校验 首先我们需要注册 Sa-Token 全局拦截器(可参考 [注解鉴权](/use/at-check) 章节),然后我们就可以使用以下注解校验账号是否封禁 ``` java +// 校验当前账号是否被封禁,如果已被封禁会抛出异常,无法进入方法 +@SaCheckDisable +@PostMapping("send") +public SaResult send() { + // ... + return SaResult.ok(); +} + // 校验当前账号是否被封禁 comment 服务,如果已被封禁会抛出异常,无法进入方法 @SaCheckDisable("comment") @PostMapping("send") @@ -131,6 +196,22 @@ public SaResult send() { // ... return SaResult.ok(); } + +// 阶梯封禁,校验当前账号封禁等级是否达到5级,如果达到则抛出异常 +@SaCheckDisable(level = 5) +@PostMapping("send") +public SaResult send() { + // ... + return SaResult.ok(); +} + +// 分类封禁 + 阶梯封禁 校验:校验当前账号的 comment 服务,封禁等级是否达到5级,如果达到则抛出异常 +@SaCheckDisable(value = "comment", level = 5) +@PostMapping("send") +public SaResult send() { + // ... + return SaResult.ok(); +} ``` diff --git a/sa-token-doc/doc/up/global-listener.md b/sa-token-doc/doc/up/global-listener.md index b690d45c..495f4dde 100644 --- a/sa-token-doc/doc/up/global-listener.md +++ b/sa-token-doc/doc/up/global-listener.md @@ -57,7 +57,7 @@ public class MySaTokenListener implements SaTokenListener { /** 每次被封禁时触发 */ @Override - public void doDisable(String loginType, Object loginId, String service, long disableTime) { + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { System.out.println("---------- 自定义侦听器实现 doDisable"); } diff --git a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java index d2fd0cd2..24e03aae 100644 --- a/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java +++ b/sa-token-test/sa-token-jwt-test/src/test/java/com/pj/test/JwtForMixinTest.java @@ -207,7 +207,7 @@ public class JwtForMixinTest { // 封号 StpUtil.disable(10007, 200); Assertions.assertTrue(StpUtil.isDisable(10007)); - Assertions.assertEquals(dao.get("satoken:login:disable:login:" + 10007), DisableServiceException.BE_VALUE); + Assertions.assertEquals(dao.get("satoken:login:disable:login:" + 10007), String.valueOf(SaTokenConsts.DEFAULT_DISABLE_LEVEL)); // 解封 StpUtil.untieDisable(10007); diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java index c71d95ad..64280506 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java @@ -359,7 +359,7 @@ public class BasicsTest { // 封号 StpUtil.disable(10007, 200); Assertions.assertTrue(StpUtil.isDisable(10007)); - Assertions.assertEquals(dao.get("satoken:login:disable:login:" + 10007), DisableServiceException.BE_VALUE); + Assertions.assertEquals(dao.get("satoken:login:disable:login:" + 10007), String.valueOf(SaTokenConsts.DEFAULT_DISABLE_LEVEL)); // 封号后检测一下 (会抛出 DisableLoginException 异常) Assertions.assertThrows(DisableServiceException.class, () -> StpUtil.checkDisable(10007)); @@ -375,13 +375,13 @@ public class BasicsTest { Assertions.assertDoesNotThrow(() -> StpUtil.checkDisable(10007)); } - // 测试:账号封禁,根据服务 + // 测试:分类封禁 @Test public void testDisableService() { // 封掉评论功能 StpUtil.disable(10008, "comment", 200); Assertions.assertTrue(StpUtil.isDisable(10008, "comment")); - Assertions.assertEquals(dao.get("satoken:login:disable:comment:" + 10008), DisableServiceException.BE_VALUE); + Assertions.assertEquals(dao.get("satoken:login:disable:comment:" + 10008), String.valueOf(SaTokenConsts.DEFAULT_DISABLE_LEVEL)); Assertions.assertNull(dao.get("satoken:login:disable:login:" + 10008)); // 封号后检测一下 @@ -405,6 +405,77 @@ public class BasicsTest { Assertions.assertDoesNotThrow(() -> StpUtil.checkDisable(10007, "comment")); } + // 测试:阶梯封禁 + @Test + public void testDisableLevel() { + // 封禁等级5 + StpUtil.disableLevel(10009, 5, 200); + Assertions.assertTrue(StpUtil.isDisableLevel(10009, 3)); + Assertions.assertTrue(StpUtil.isDisableLevel(10009, 5)); + // 未达到7级 + Assertions.assertFalse(StpUtil.isDisableLevel(10009, 7)); + // 账号未封禁 + Assertions.assertFalse(StpUtil.isDisableLevel(20009, 3)); + + // dao中应该有值 + Assertions.assertEquals(dao.get("satoken:login:disable:login:" + 10009), String.valueOf(5)); + + // 封号后检测一下 + Assertions.assertThrows(DisableServiceException.class, () -> StpUtil.checkDisableLevel(10009, 3)); + Assertions.assertThrows(DisableServiceException.class, () -> StpUtil.checkDisableLevel(10009, 5)); + // 未达到等级,不抛出异常 + Assertions.assertDoesNotThrow(() -> StpUtil.checkDisableLevel(10009, 7)); + // 账号未被封禁,不抛出异常 + Assertions.assertDoesNotThrow(() -> StpUtil.checkDisableLevel(20009, 3)); + + // 封号等级 + Assertions.assertEquals(StpUtil.getDisableLevel(10009), 5); + Assertions.assertEquals(StpUtil.getDisableLevel(20009), -2); + + // 解封 + StpUtil.untieDisable(10009); + Assertions.assertFalse(StpUtil.isDisable(10009)); + Assertions.assertFalse(StpUtil.isDisableLevel(10009, 5)); + Assertions.assertNull(dao.get("satoken:login:disable:login:" + 10009)); + } + + // 测试:分类封禁 + 阶梯封禁 + @Test + public void testDisableServiceLevel() { + // 封禁服务 shop,等级5 + StpUtil.disableLevel(10010, "shop", 5, 200); + Assertions.assertTrue(StpUtil.isDisableLevel(10010, "shop", 3)); + Assertions.assertTrue(StpUtil.isDisableLevel(10010, "shop", 5)); + // 未达到7级 + Assertions.assertFalse(StpUtil.isDisableLevel(10010, "shop", 7)); + // 账号未封禁 + Assertions.assertFalse(StpUtil.isDisableLevel(20010, "shop", 3)); + // 服务名不对 + Assertions.assertFalse(StpUtil.isDisableLevel(10010, "shop2", 5)); + + // dao中应该有值 + Assertions.assertEquals(dao.get("satoken:login:disable:shop:" + 10010), String.valueOf(5)); + + // 封号后检测一下 + Assertions.assertThrows(DisableServiceException.class, () -> StpUtil.checkDisableLevel(10010, "shop", 3)); + Assertions.assertThrows(DisableServiceException.class, () -> StpUtil.checkDisableLevel(10010, "shop", 5)); + // 未达到等级,不抛出异常 + Assertions.assertDoesNotThrow(() -> StpUtil.checkDisableLevel(10010, "shop", 7)); + // 账号未被封禁,不抛出异常 + Assertions.assertDoesNotThrow(() -> StpUtil.checkDisableLevel(20010, "shop", 3)); + + // 封号等级 + Assertions.assertEquals(StpUtil.getDisableLevel(10010, "shop"), 5); + Assertions.assertEquals(StpUtil.getDisableLevel(10010, "shop2"), -2); + Assertions.assertEquals(StpUtil.getDisableLevel(20010, "shop"), -2); + + // 解封 + StpUtil.untieDisable(10010, "shop"); + Assertions.assertFalse(StpUtil.isDisable(10010, "shop")); + Assertions.assertFalse(StpUtil.isDisableLevel(10010, "shop", 5)); + Assertions.assertNull(dao.get("satoken:login:disable:shop:" + 10010)); + } + // 测试:身份切换 @Test public void testSwitch() {