update sa-token 1.45.0 => 1.46.0

This commit is contained in:
疯狂的狮子Li 2026-09-24 14:06:51 +08:00
parent de394a0e21
commit 8fc48f013f
4 changed files with 36 additions and 6 deletions

View File

@ -35,7 +35,7 @@
<elasticsearch-client.version>7.17.28</elasticsearch-client.version> <elasticsearch-client.version>7.17.28</elasticsearch-client.version>
<!-- 安全认证与加密相关依赖版本 --> <!-- 安全认证与加密相关依赖版本 -->
<satoken.version>1.45.0</satoken.version> <satoken.version>1.46.0</satoken.version>
<justauth.version>3.0.1</justauth.version> <justauth.version>3.0.1</justauth.version>
<bouncycastle.version>1.85</bouncycastle.version> <bouncycastle.version>1.85</bouncycastle.version>

View File

@ -23,6 +23,12 @@ public class LoginUser implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 登录标识分隔符,用于拼接 userType 与 userId
* <p>不使用冒号:Sa-Token 1.46.0 起默认禁止 loginId 包含冒号;历史冒号格式仅为兼容旧 token 保留解析
*/
public static final String LOGIN_ID_SEPARATOR = "-";
/** /**
* 用户ID * 用户ID
*/ */
@ -136,7 +142,7 @@ public class LoginUser implements Serializable {
/** /**
* 获取 Sa-Token 使用的登录标识。 * 获取 Sa-Token 使用的登录标识。
* *
* @return 登录标识 * @return 登录标识(userType-userId)
*/ */
public String getLoginId() { public String getLoginId() {
if (userType == null) { if (userType == null) {
@ -145,7 +151,7 @@ public class LoginUser implements Serializable {
if (userId == null) { if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空"); throw new IllegalArgumentException("用户ID不能为空");
} }
return userType + ":" + userId; return userType + LOGIN_ID_SEPARATOR + userId;
} }
} }

View File

@ -57,7 +57,7 @@ public class SaPermissionImpl implements StpInterface {
java.util.function.Function<LoginUser, Collection<String>> localPermissionExtractor, java.util.function.Function<LoginUser, Collection<String>> localPermissionExtractor,
BiFunction<PermissionService, Long, Collection<String>> remotePermissionExtractor) { BiFunction<PermissionService, Long, Collection<String>> remotePermissionExtractor) {
LoginUser loginUser = LoginHelper.getLoginUser(); LoginUser loginUser = LoginHelper.getLoginUser();
if (ObjectUtil.isNull(loginUser) || !loginUser.getLoginId().equals(loginId)) { if (ObjectUtil.isNull(loginUser) || !loginUser.getLoginId().equals(normalizeLoginId(loginId))) {
PermissionService permissionService = getPermissionService(); PermissionService permissionService = getPermissionService();
if (ObjectUtil.isNotNull(permissionService)) { if (ObjectUtil.isNotNull(permissionService)) {
return new ArrayList<>(remotePermissionExtractor.apply(permissionService, resolveUserId(loginId))); 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 * @param loginId 登录ID
* @return 用户ID * @return 用户ID
@ -93,6 +108,9 @@ public class SaPermissionImpl implements StpInterface {
private Long resolveUserId(Object loginId) { private Long resolveUserId(Object loginId) {
String loginIdStr = loginId.toString(); String loginIdStr = loginId.toString();
int separatorIndex = loginIdStr.indexOf(':'); int separatorIndex = loginIdStr.indexOf(':');
if (separatorIndex < 0) {
separatorIndex = loginIdStr.lastIndexOf(LoginUser.LOGIN_ID_SEPARATOR);
}
if (separatorIndex < 0 || separatorIndex == loginIdStr.length() - 1) { if (separatorIndex < 0 || separatorIndex == loginIdStr.length() - 1) {
throw new ServiceException("登录ID格式错误"); throw new ServiceException("登录ID格式错误");
} }

View File

@ -74,6 +74,7 @@ class SaTokenFunctionTest {
/** /**
* 验证当前登录对象的菜单和角色权限直接来自会话快照,并对空权限集合返回可修改空列表。 * 验证当前登录对象的菜单和角色权限直接来自会话快照,并对空权限集合返回可修改空列表。
* 历史冒号格式与当前分隔符格式的登录ID均应命中会话快照。
*/ */
@Test @Test
@DisplayName("读取当前会话权限快照") @DisplayName("读取当前会话权限快照")
@ -94,6 +95,10 @@ class SaTokenFunctionTest {
assertEquals(Set.of("system:user:list", "system:user:add"), Set.copyOf(menus)); assertEquals(Set.of("system:user:list", "system:user:add"), Set.copyOf(menus));
assertEquals(List.of(), roles); assertEquals(List.of(), roles);
roles.add("temporary"); 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(); 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"));
assertEquals(List.of("system:dept:list"), permission.getPermissionList("sys_user-9", "login"));
assertThrows(ServiceException.class, () -> permission.getPermissionList("invalid", "login")); assertThrows(ServiceException.class, () -> permission.getPermissionList("invalid", "login"));
verify(service).getMenuPermission(9L); verify(service, times(2)).getMenuPermission(9L);
} }
} }