新增部分 TokenSign 相关方法,更方便的操作管理会话

This commit is contained in:
click33
2023-06-07 15:49:04 +08:00
parent b43fa1a1c9
commit f59b1b3885
5 changed files with 142 additions and 68 deletions

View File

@@ -15,20 +15,16 @@
*/
package cn.dev33.satoken.session;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.application.SaSetValueInterface;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Session Model会话作用域的读取值对象
*
@@ -277,14 +273,15 @@ public class SaSession implements SaSetValueInterface, Serializable {
* @param device 设备类型,填 null 代表不限设备类型
* @return token签名列表
*/
public List<TokenSign> tokenSignListCopyByDevice(String device) {
public List<TokenSign> getTokenSignListByDevice(String device) {
// 返回全部
if(device == null) {
return tokenSignListCopy();
}
// 返回筛选后的
// 返回筛选后的
List<TokenSign> tokenSignList = tokenSignListCopy();
List<TokenSign> list = new ArrayList<>();
for (TokenSign tokenSign : tokenSignListCopy()) {
for (TokenSign tokenSign : tokenSignList) {
if(SaFoxUtil.equals(tokenSign.getDevice(), device)) {
list.add(tokenSign);
}
@@ -292,6 +289,24 @@ public class SaSession implements SaSetValueInterface, Serializable {
return list;
}
/**
* 获取当前 Session 上的所有 token 列表
*
* @param device 设备类型,填 null 代表不限设备类型
* @return 此 loginId 的所有登录 token
*/
public List<String> getTokenValueListByDevice(String device) {
// 遍历解析,按照设备类型进行筛选
List<TokenSign> tokenSignList = tokenSignListCopy();
List<String> tokenValueList = new ArrayList<>();
for (TokenSign tokenSign : tokenSignList) {
if(device == null || tokenSign.getDevice().equals(device)) {
tokenValueList.add(tokenSign.getValue());
}
}
return tokenValueList;
}
/**
* 查找一个 Token 签名
*
@@ -313,13 +328,18 @@ public class SaSession implements SaSetValueInterface, Serializable {
* @param tokenSign Token 签名
*/
public void addTokenSign(TokenSign tokenSign) {
// 如果已经存在于列表中,则无需再次添加
if(getTokenSign(tokenSign.getValue()) != null) {
return;
// 根据 tokenValue 值查重,如果不存在,则添加
TokenSign oldTokenSign = getTokenSign(tokenSign.getValue());
if(oldTokenSign == null) {
tokenSignList.add(tokenSign);
update();
} else {
// 如果存在,则更新
oldTokenSign.setValue(tokenSign.getValue());
oldTokenSign.setDevice(tokenSign.getDevice());
oldTokenSign.setTag(tokenSign.getTag());
update();
}
// 添加并更新
tokenSignList.add(tokenSign);
update();
}
/**
@@ -512,4 +532,18 @@ public class SaSession implements SaSetValueInterface, Serializable {
this.update();
}
//
/**
* 请更换为getTokenSignListByDevice(device)
*
* @param device 设备类型,填 null 代表不限设备类型
* @return token签名列表
*/
@Deprecated
public List<TokenSign> tokenSignListCopyByDevice(String device) {
return getTokenSignListByDevice(device);
}
}

View File

@@ -36,7 +36,6 @@ import cn.dev33.satoken.util.SaFoxUtil;
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;
@@ -490,8 +489,8 @@ public class StpLogic {
// 3.1、看看全局配置的 IsShare 参数,配置为 true 才是允许复用旧 token
if(getConfigOfIsShare()) {
// 根据账号id + 设备标识,尝试获取旧的 token
String tokenValue = getTokenValueByLoginId(id, loginModel.getDeviceOrDefault());
// 根据账号id尝试获取旧的 token
String tokenValue = getTokenValueByLoginId(id, null);
// 如果有值,那就直接复用
if(SaFoxUtil.isNotEmpty(tokenValue)) {
@@ -605,7 +604,7 @@ public class StpLogic {
if(session != null) {
// 2、遍历此账号所有从这个 device 设备上登录的客户端,清除相关数据
for (TokenSign tokenSign: session.tokenSignListCopyByDevice(device)) {
for (TokenSign tokenSign: session.getTokenSignListByDevice(device)) {
// 2.1、获取此客户端的 token 值
String tokenValue = tokenSign.getValue();
@@ -652,7 +651,7 @@ public class StpLogic {
}
// 2、获取这个账号指定设备类型下的所有登录客户端
List<TokenSign> list = session.tokenSignListCopyByDevice(device);
List<TokenSign> list = session.getTokenSignListByDevice(device);
// 3、按照登录时间倒叙超过 maxLoginCount 数量的,全部注销掉
for (int i = 0; i < list.size() - maxLoginCount; i++) {
@@ -741,7 +740,7 @@ public class StpLogic {
if(session != null) {
// 2、遍历此账号所有从这个 device 设备上登录的客户端,清除相关数据
for (TokenSign tokenSign: session.tokenSignListCopyByDevice(device)) {
for (TokenSign tokenSign: session.getTokenSignListByDevice(device)) {
// 2.1、获取此客户端的 token 值
String tokenValue = tokenSign.getValue();
@@ -817,7 +816,7 @@ public class StpLogic {
if(session != null) {
// 2、遍历此账号所有从这个 device 设备上登录的客户端,清除相关数据
for (TokenSign tokenSign: session.tokenSignListCopyByDevice(device)) {
for (TokenSign tokenSign: session.getTokenSignListByDevice(device)) {
// 2.1、获取此客户端的 token 值
String tokenValue = tokenSign.getValue();
@@ -858,8 +857,18 @@ public class StpLogic {
// 2、并且不在异常项集合里此项在 getLoginIdDefaultNull() 方法里完成判断)
return getLoginIdDefaultNull() != null;
}
/**
/**
* 判断指定账号是否已经登录
*
* @return 已登录返回 true未登录返回 false
*/
public boolean isLogin(Object loginId) {
// 判断条件:能否根据 loginId 查询到对应的 tokenSign 值
return getTokenSignListByLoginId(loginId, null).size() > 0;
}
/**
* 检验当前会话是否已经登录,如未登录,则抛出异常
*/
public void checkLogin() {
@@ -1989,17 +1998,28 @@ public class StpLogic {
return Collections.emptyList();
}
// 遍历解析,按照设备类型进行筛选
List<TokenSign> tokenSignList = session.tokenSignListCopy();
List<String> tokenValueList = new ArrayList<>();
for (TokenSign tokenSign : tokenSignList) {
if(device == null || tokenSign.getDevice().equals(device)) {
tokenValueList.add(tokenSign.getValue());
}
}
return tokenValueList;
// 按照设备类型进行筛选
return session.getTokenValueListByDevice(device);
}
/**
* 获取指定账号 id 指定设备类型端的 tokenSign 集合
*
* @param loginId 账号id
* @param device 设备类型,填 null 代表不限设备类型
* @return 此 loginId 的所有登录 token
*/
public List<TokenSign> getTokenSignListByLoginId(Object loginId, String device) {
// 如果该账号的 Account-Session 为 null说明此账号尚没有客户端在登录此时返回空集合
SaSession session = getSessionByLoginId(loginId, false);
if(session == null) {
return Collections.emptyList();
}
// 按照设备类型进行筛选
return session.getTokenSignListByDevice(device);
}
/**
* 返回当前会话的登录设备类型
*

View File

@@ -19,7 +19,9 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.TokenSign;
import java.util.Collections;
import java.util.List;
/**
@@ -314,6 +316,15 @@ public class StpUtil {
return stpLogic.isLogin();
}
/**
* 判断指定账号是否已经登录
*
* @return 已登录返回 true未登录返回 false
*/
public static boolean isLogin(Object loginId) {
return stpLogic.isLogin(loginId);
}
/**
* 检验当前会话是否已经登录,如未登录,则抛出异常
*/
@@ -814,6 +825,17 @@ public class StpUtil {
return stpLogic.getTokenValueListByLoginId(loginId, device);
}
/**
* 获取指定账号 id 指定设备类型端的 tokenSign 集合
*
* @param loginId 账号id
* @param device 设备类型,填 null 代表不限设备类型
* @return 此 loginId 的所有登录 tokenSign
*/
public static List<TokenSign> getTokenSignListByLoginId(Object loginId, String device) {
return stpLogic.getTokenSignListByLoginId(loginId, device);
}
/**
* 返回当前会话的登录设备类型
*

View File

@@ -29,21 +29,20 @@ import cn.dev33.satoken.util.SaTokenConsts;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Function;
/**
* Sa-Token 策略对象
* Sa-Token 策略对象
* <p>
* 此类统一定义框架内的一些关键性逻辑算法,方便开发者进行按需重写,例:
* </p>
* <pre>
// SaStrategy全局单例所有方法都用以下形式重写
SaStrategy.instance.setCreateToken((loginId, loginType) -》 {
// 自定义Token生成的算法
return "xxxx";
});
// SaStrategy全局单例所有方法都用以下形式重写
SaStrategy.instance.setCreateToken((loginId, loginType) -》 {
// 自定义Token生成的算法
return "xxxx";
});
* </pre>
*
*
* @author click33
* @since 1.27.0
*/
@@ -53,18 +52,18 @@ public final class SaStrategy {
}
/**
* 获取 SaStrategy 对象的单例引用
* 获取 SaStrategy 对象的单例引用
*/
public static final SaStrategy instance = new SaStrategy();
// ----------------------- 所有策略
/**
* 创建 Token 的策略
*/
public SaCreateTokenFunction createToken = (loginId, loginType) -> {
// 根据配置的tokenStyle生成不同风格的token
// 根据配置的tokenStyle生成不同风格的token
String tokenStyle = SaManager.getConfig().getTokenStyle();
switch (tokenStyle) {
@@ -99,7 +98,7 @@ public final class SaStrategy {
return UUID.randomUUID().toString();
}
};
/**
* 创建 Session 的策略
*/
@@ -117,19 +116,19 @@ public final class SaStrategy {
return false;
}
// 先尝试一下简单匹配,如果可以匹配成功则无需继续模糊匹配
// 先尝试一下简单匹配,如果可以匹配成功则无需继续模糊匹配
if (list.contains(element)) {
return true;
}
// 开始模糊匹配
// 开始模糊匹配
for (String patt : list) {
if(SaFoxUtil.vagueMatch(patt, element)) {
return true;
}
}
// 走出for循环说明没有一个元素可以匹配成功
// 走出for循环说明没有一个元素可以匹配成功
return false;
};
@@ -138,10 +137,10 @@ public final class SaStrategy {
*/
public SaCheckMethodAnnotationFunction checkMethodAnnotation = (method) -> {
// 先校验 Method 所属 Class 上的注解
// 先校验 Method 所属 Class 上的注解
instance.checkElementAnnotation.accept(method.getDeclaringClass());
// 再校验 Method 上的注解
// 再校验 Method 上的注解
instance.checkElementAnnotation.accept(method);
};
@@ -150,18 +149,18 @@ public final class SaStrategy {
*/
public SaCheckElementAnnotationFunction checkElementAnnotation = (element) -> {
// 校验 @SaCheckLogin 注解
// 校验 @SaCheckLogin 注解
SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.instance.getAnnotation.apply(element, SaCheckLogin.class);
if(checkLogin != null) {
SaManager.getStpLogic(checkLogin.type(), false).checkByAnnotation(checkLogin);
}
// 校验 @SaCheckRole 注解
// 校验 @SaCheckRole 注解
SaCheckRole checkRole = (SaCheckRole) SaStrategy.instance.getAnnotation.apply(element, SaCheckRole.class);
if(checkRole != null) {
SaManager.getStpLogic(checkRole.type(), false).checkByAnnotation(checkRole);
}
// 校验 @SaCheckPermission 注解
SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.instance.getAnnotation.apply(element, SaCheckPermission.class);
if(checkPermission != null) {
@@ -179,7 +178,7 @@ public final class SaStrategy {
if(checkDisable != null) {
SaManager.getStpLogic(checkDisable.type(), false).checkByAnnotation(checkDisable);
}
// 校验 @SaCheckBasic 注解
SaCheckBasic checkBasic = (SaCheckBasic) SaStrategy.instance.getAnnotation.apply(element, SaCheckBasic.class);
if(checkBasic != null) {
@@ -283,7 +282,7 @@ public final class SaStrategy {
* 从元素上获取注解
*/
public SaGetAnnotationFunction getAnnotation = (element, annotationClass)->{
// 默认使用jdk的注解处理器
// 默认使用jdk的注解处理器
return element.getAnnotation(annotationClass);
};
@@ -337,7 +336,7 @@ public final class SaStrategy {
/**
* 重写创建 Token 的策略
*
* @param createToken /
* @param createToken /
* @return /
*/
public SaStrategy setCreateToken(SaCreateTokenFunction createToken) {
@@ -348,7 +347,7 @@ public final class SaStrategy {
/**
* 重写创建 Session 的策略
*
* @param createSession /
* @param createSession /
* @return /
*/
public SaStrategy setCreateSession(SaCreateSessionFunction createSession) {
@@ -381,7 +380,7 @@ public final class SaStrategy {
/**
* 对一个 [元素] 对象进行注解校验 (注解鉴权内部实现)
*
* @param checkElementAnnotation /
* @param checkElementAnnotation /
* @return /
*/
public SaStrategy setCheckElementAnnotation(SaCheckElementAnnotationFunction checkElementAnnotation) {
@@ -404,7 +403,7 @@ public final class SaStrategy {
/**
* 从元素上获取注解
*
* @param getAnnotation /
* @param getAnnotation /
* @return /
*/
public SaStrategy setGetAnnotation(SaGetAnnotationFunction getAnnotation) {
@@ -415,7 +414,7 @@ public final class SaStrategy {
/**
* 判断一个 Method 或其所属 Class 是否包含指定注解
*
* @param isAnnotationPresent /
* @param isAnnotationPresent /
* @return /
*/
public SaStrategy setIsAnnotationPresent(SaIsAnnotationPresentFunction isAnnotationPresent) {