From 8fc48f013ff8306fd7ef54de85a2d3c76808894b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?=
<15040126243@163.com>
Date: Thu, 24 Sep 2026 14:06:51 +0800
Subject: [PATCH] update sa-token 1.45.0 => 1.46.0
---
pom.xml | 2 +-
.../dromara/system/api/model/LoginUser.java | 10 +++++++--
.../core/service/SaPermissionImpl.java | 22 +++++++++++++++++--
.../common/satoken/SaTokenFunctionTest.java | 8 ++++++-
4 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/pom.xml b/pom.xml
index 449030ab7..f31ed993f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,7 @@
7.17.28
- 1.45.0
+ 1.46.0
3.0.1
1.85
diff --git a/ruoyi-api/src/main/java/org/dromara/system/api/model/LoginUser.java b/ruoyi-api/src/main/java/org/dromara/system/api/model/LoginUser.java
index 352e330cd..91f5fd8e9 100644
--- a/ruoyi-api/src/main/java/org/dromara/system/api/model/LoginUser.java
+++ b/ruoyi-api/src/main/java/org/dromara/system/api/model/LoginUser.java
@@ -23,6 +23,12 @@ public class LoginUser implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
+ /**
+ * 登录标识分隔符,用于拼接 userType 与 userId
+ *
不使用冒号:Sa-Token 1.46.0 起默认禁止 loginId 包含冒号;历史冒号格式仅为兼容旧 token 保留解析
+ */
+ public static final String LOGIN_ID_SEPARATOR = "-";
+
/**
* 用户ID
*/
@@ -136,7 +142,7 @@ public class LoginUser implements Serializable {
/**
* 获取 Sa-Token 使用的登录标识。
*
- * @return 登录标识
+ * @return 登录标识(userType-userId)
*/
public String getLoginId() {
if (userType == null) {
@@ -145,7 +151,7 @@ public class LoginUser implements Serializable {
if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
- return userType + ":" + userId;
+ return userType + LOGIN_ID_SEPARATOR + userId;
}
}
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java
index ddd4c1f4b..b9356a616 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java
@@ -57,7 +57,7 @@ public class SaPermissionImpl implements StpInterface {
java.util.function.Function> localPermissionExtractor,
BiFunction> remotePermissionExtractor) {
LoginUser loginUser = LoginHelper.getLoginUser();
- if (ObjectUtil.isNull(loginUser) || !loginUser.getLoginId().equals(loginId)) {
+ if (ObjectUtil.isNull(loginUser) || !loginUser.getLoginId().equals(normalizeLoginId(loginId))) {
PermissionService permissionService = getPermissionService();
if (ObjectUtil.isNotNull(permissionService)) {
return new ArrayList<>(remotePermissionExtractor.apply(permissionService, resolveUserId(loginId)));
@@ -85,7 +85,22 @@ public class SaPermissionImpl implements StpInterface {
}
/**
- * 从登录ID中提取用户ID。
+ * 将历史冒号格式的登录ID规范化为当前分隔符格式,保证与旧 token 会话比较的一致性。
+ *
+ * @param loginId 登录ID
+ * @return 规范化后的登录ID
+ */
+ private String normalizeLoginId(Object loginId) {
+ String loginIdStr = loginId.toString();
+ int separatorIndex = loginIdStr.indexOf(':');
+ if (separatorIndex < 0) {
+ return loginIdStr;
+ }
+ return loginIdStr.substring(0, separatorIndex) + LoginUser.LOGIN_ID_SEPARATOR + loginIdStr.substring(separatorIndex + 1);
+ }
+
+ /**
+ * 从登录ID中提取用户ID,兼容历史冒号格式与当前分隔符格式。
*
* @param loginId 登录ID
* @return 用户ID
@@ -93,6 +108,9 @@ public class SaPermissionImpl implements StpInterface {
private Long resolveUserId(Object loginId) {
String loginIdStr = loginId.toString();
int separatorIndex = loginIdStr.indexOf(':');
+ if (separatorIndex < 0) {
+ separatorIndex = loginIdStr.lastIndexOf(LoginUser.LOGIN_ID_SEPARATOR);
+ }
if (separatorIndex < 0 || separatorIndex == loginIdStr.length() - 1) {
throw new ServiceException("登录ID格式错误");
}
diff --git a/ruoyi-common/ruoyi-common-satoken/src/test/java/org/dromara/common/satoken/SaTokenFunctionTest.java b/ruoyi-common/ruoyi-common-satoken/src/test/java/org/dromara/common/satoken/SaTokenFunctionTest.java
index 1276572ef..44be2eaa3 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/test/java/org/dromara/common/satoken/SaTokenFunctionTest.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/test/java/org/dromara/common/satoken/SaTokenFunctionTest.java
@@ -74,6 +74,7 @@ class SaTokenFunctionTest {
/**
* 验证当前登录对象的菜单和角色权限直接来自会话快照,并对空权限集合返回可修改空列表。
+ * 历史冒号格式与当前分隔符格式的登录ID均应命中会话快照。
*/
@Test
@DisplayName("读取当前会话权限快照")
@@ -94,6 +95,10 @@ class SaTokenFunctionTest {
assertEquals(Set.of("system:user:list", "system:user:add"), Set.copyOf(menus));
assertEquals(List.of(), roles);
roles.add("temporary");
+
+ assertEquals(Set.of("system:user:list", "system:user:add"),
+ Set.copyOf(permission.getPermissionList("sys_user-7", "login")));
+ assertEquals(List.of(), permission.getRoleList("sys_user-7", "login"));
}
}
@@ -113,8 +118,9 @@ class SaTokenFunctionTest {
SaPermissionImpl permission = new SaPermissionImpl();
assertEquals(List.of("system:dept:list"), permission.getPermissionList("sys_user:9", "login"));
+ assertEquals(List.of("system:dept:list"), permission.getPermissionList("sys_user-9", "login"));
assertThrows(ServiceException.class, () -> permission.getPermissionList("invalid", "login"));
- verify(service).getMenuPermission(9L);
+ verify(service, times(2)).getMenuPermission(9L);
}
}