feat(core): 封禁模块新增支持实时从数据库查询数据

This commit is contained in:
click33
2025-01-11 21:49:58 +08:00
parent a4be9928aa
commit 5c0ca64a00
4 changed files with 154 additions and 15 deletions

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.model.wrapperInfo;
/**
* 返回值包装类:描述一个账号是否已被封禁等信息
*
* @author click33
* @since 1.40.0
*/
public class SaDisableWrapperInfo {
/**
* 是否被封禁
*/
public boolean isDisable;
/**
* 封禁剩余时间,单位:秒(-1=永久封禁0 or -2=未封禁)
*/
public long disableTime;
/**
* 封禁等级最小1级0=未封禁)
*/
public int disableLevel;
/**
* 构建对象
*
* @param isDisable 是否被封禁
* @param disableTime 封禁剩余时间,单位:秒(-1=永久封禁0 or -2=未封禁)
* @param disableLevel 封禁等级最小1级0=未封禁)
*/
public SaDisableWrapperInfo(boolean isDisable, long disableTime, int disableLevel) {
this.isDisable = isDisable;
this.disableTime = disableTime;
this.disableLevel = disableLevel;
}
/**
* 创建一个已封禁描述对象
* @param disableTime 封禁时间
* @param disableLevel 封禁等级
* @return /
*/
public static SaDisableWrapperInfo createDisabled(long disableTime, int disableLevel) {
return new SaDisableWrapperInfo(true, disableTime, disableLevel);
}
/**
* 创建一个未封禁描述对象
* @return /
*/
public static SaDisableWrapperInfo createNotDisabled() {
return new SaDisableWrapperInfo(false, 0, 0);
}
/**
* 创建一个未封禁描述对象,并指定缓存时间,指定时间内不再重复查询
* @param cacheTime 缓存时间(单位:秒)
* @return /
*/
public static SaDisableWrapperInfo createNotDisabled(long cacheTime) {
return new SaDisableWrapperInfo(false, cacheTime, 0);
}
@Override
public String toString() {
return "SaDisableWrapperInfo{" +
"isDisable=" + isDisable +
", disableTime=" + disableTime +
", disableLevel=" + disableLevel +
'}';
}
// setter / getter 仅为兼容部分框架序列化操作,不建议调用
public boolean getIsDisable() {
return isDisable;
}
public SaDisableWrapperInfo setIsDisable(boolean isDisable) {
this.isDisable = isDisable;
return this;
}
public long getDisableTime() {
return disableTime;
}
public SaDisableWrapperInfo setDisableTime(long disableTime) {
this.disableTime = disableTime;
return this;
}
public int getDisableLevel() {
return disableLevel;
}
public SaDisableWrapperInfo setDisableLevel(int disableLevel) {
this.disableLevel = disableLevel;
return this;
}
}

View File

@@ -15,10 +15,12 @@
*/
package cn.dev33.satoken.stp;
import cn.dev33.satoken.model.wrapperInfo.SaDisableWrapperInfo;
import java.util.List;
/**
* 权限数据加载接口
* 权限数据加载接口
*
* <p>
* 在使用权限校验 API 之前,你必须实现此接口,告诉框架哪些用户拥有哪些权限。<br>
@@ -48,4 +50,15 @@ public interface StpInterface {
*/
List<String> getRoleList(Object loginId, String loginType);
/**
* 返回指定账号 id 是否被封禁
*
* @param loginId 账号id
* @param service 业务标识符
* @return 描述该账号是否封禁的包装信息对象
*/
default SaDisableWrapperInfo isDisabled(Object loginId, String service) {
return SaDisableWrapperInfo.createNotDisabled();
}
}

View File

@@ -29,6 +29,7 @@ import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.*;
import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.model.wrapperInfo.SaDisableWrapperInfo;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.TokenSign;
import cn.dev33.satoken.strategy.SaStrategy;
@@ -2413,8 +2414,8 @@ public class StpLogic {
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);
if(level < SaTokenConsts.MIN_DISABLE_LEVEL && level != 0) {
throw new SaTokenException("封禁等级不可以小于最小值:" + SaTokenConsts.MIN_DISABLE_LEVEL + " (0除外)").setCode(SaErrorCode.CODE_11064);
}
// 打上封禁标记
@@ -2473,13 +2474,12 @@ public class StpLogic {
*/
public void checkDisableLevel(Object loginId, String service, int level) {
// 1、先前置检查一下这个账号是否被封禁了
String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));
if(SaFoxUtil.isEmpty(value)) {
int disableLevel = getDisableLevel(loginId, service);
if(disableLevel == SaTokenConsts.NOT_DISABLE_LEVEL) {
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);
@@ -2504,14 +2504,22 @@ public class StpLogic {
* @return /
*/
public int getDisableLevel(Object loginId, String service) {
// 1、判断是否被封禁了,如果尚未被封禁,返回-2
// 1、先从缓存中查询数据,缓存中有值,以缓存值优先
String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));
if(SaFoxUtil.isEmpty(value)) {
return SaTokenConsts.NOT_DISABLE_LEVEL;
if(SaFoxUtil.isNotEmpty(value)) {
return SaFoxUtil.getValueByType(value, int.class);
}
// 2、转为 int 类型返回
return SaFoxUtil.getValueByType(value, int.class);
// 2、如果缓存中无数据,则从"数据加载器"中再次查询
SaDisableWrapperInfo disableWrapperInfo = SaManager.getStpInterface().isDisabled(loginId, service);
// 如果返回值 disableTime 有效,则代表返回结果需要写入缓存
if(disableWrapperInfo.disableTime == SaTokenDao.NEVER_EXPIRE || disableWrapperInfo.disableTime > 0) {
disableLevel(loginId, service, disableWrapperInfo.disableLevel, disableWrapperInfo.disableTime);
}
// 返回查询结果
return disableWrapperInfo.disableLevel;
}