mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-08 06:05:33 +08:00
feat(iam): 打通会话管理配置到登录链路
TokenService.doSaLogin 读取 PlatformSessionManagementConfig 并应用: 在线时长->timeout, 活跃超时->activeTimeout, 三种并发策略(KICK_OLDEST/DENY_NEW/NEW_SESSION); enabled=false时回退yml默认; 新增activeTimeoutHours字段与concurrentLimitExceeded文案
This commit is contained in:
@@ -26,5 +26,6 @@
|
||||
"tokenTimeout": "Session expired, please log in again",
|
||||
"beReplaced": "Account signed in on another device",
|
||||
"kickOut": "Session no longer valid, please log in again",
|
||||
"tokenFreeze": "Authentication credential frozen"
|
||||
"tokenFreeze": "Authentication credential frozen",
|
||||
"concurrentLimitExceeded": "Concurrent login limit reached, please sign out from another device first"
|
||||
}
|
||||
|
||||
@@ -26,5 +26,6 @@
|
||||
"tokenTimeout": "登录已过期,请重新登录",
|
||||
"beReplaced": "账号已在其他设备登录",
|
||||
"kickOut": "登录状态已失效,请重新登录",
|
||||
"tokenFreeze": "登录凭证已被冻结"
|
||||
"tokenFreeze": "登录凭证已被冻结",
|
||||
"concurrentLimitExceeded": "并发登录数已达上限,请先退出其他设备"
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import cn.daxpay.open.platform.iam.exception.auth.ApplicationNotFoundException;
|
||||
import cn.daxpay.open.platform.iam.result.user.UserInfoResult;
|
||||
import cn.daxpay.open.platform.iam.service.twofactor.UserTwoFactorService;
|
||||
import cn.daxpay.open.platform.iam.service.user.UserQueryService;
|
||||
import cn.daxpay.open.platform.system.entity.config.platform.security.PlatformSessionManagementConfig;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
@@ -56,6 +57,8 @@ public class TokenService {
|
||||
|
||||
private final UserQueryService userQueryService;
|
||||
|
||||
private final IamSecurityConfigService iamSecurityConfigService;
|
||||
|
||||
/// 登录
|
||||
public String login(HttpServletRequest request, HttpServletResponse response) {
|
||||
AuthInfoResult authInfoResult;
|
||||
@@ -197,6 +200,8 @@ public class TokenService {
|
||||
var saLoginModel = new SaLoginParameter()
|
||||
.setDeviceType(clientCode)
|
||||
.setIsLastingCookie(true);
|
||||
// 应用会话管理配置(在线时长/活跃超时/并发策略)
|
||||
this.applySessionConfig(saLoginModel, authInfoResult.getId());
|
||||
|
||||
authInfoResult.setClient(clientCode)
|
||||
.setLoginType(loginType);
|
||||
@@ -206,6 +211,43 @@ public class TokenService {
|
||||
session.set(CommonCode.USER, userDetail);
|
||||
}
|
||||
|
||||
/// 应用会话管理配置到 Sa-Token 登录参数
|
||||
/// 配置未启用时跳过, 继续使用 application.yml 中的静态默认值
|
||||
private void applySessionConfig(SaLoginParameter model, Object userId) {
|
||||
PlatformSessionManagementConfig config = iamSecurityConfigService.getSessionManagement();
|
||||
if (config == null || !Boolean.TRUE.equals(config.getEnabled())) {
|
||||
return;
|
||||
}
|
||||
// 在线时长 -> token 固定有效期(秒)
|
||||
if (config.getMaxOnlineHours() != null && config.getMaxOnlineHours() > 0) {
|
||||
model.setTimeout(config.getMaxOnlineHours() * 3600L);
|
||||
}
|
||||
// 活跃超时 -> 无操作超时(秒), 0或null表示不限制
|
||||
if (config.getActiveTimeoutHours() != null && config.getActiveTimeoutHours() > 0) {
|
||||
model.setActiveTimeout(config.getActiveTimeoutHours() * 3600L);
|
||||
}
|
||||
// 并发登录策略
|
||||
Integer max = config.getMaxConcurrentSessions();
|
||||
String strategy = config.getConcurrentStrategy();
|
||||
if ("KICK_OLDEST".equals(strategy) && max != null && max > 0) {
|
||||
// 允许并发, 超出上限时 Sa-Token 自动注销最早的会话
|
||||
model.setIsConcurrent(true).setMaxLoginCount(max);
|
||||
}
|
||||
else if ("DENY_NEW".equals(strategy) && max != null && max > 0) {
|
||||
// 登录前预检: 已达上限则拒绝新登录
|
||||
int current = StpUtil.getTokenValueListByLoginId(userId).size();
|
||||
if (current >= max) {
|
||||
throw new LoginFailureException("error.auth.concurrentLimitExceeded");
|
||||
}
|
||||
// 不设 maxLoginCount, 保持"拒绝"语义, 避免触发 Sa-Token 自动踢旧
|
||||
model.setIsConcurrent(true);
|
||||
}
|
||||
else {
|
||||
// NEW_SESSION 或未配置策略: 允许并发, 不限制数量
|
||||
model.setIsConcurrent(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// 退出
|
||||
public void logout() {
|
||||
StpUtil.logout();
|
||||
|
||||
@@ -13,6 +13,8 @@ public class PlatformSessionManagementConfig {
|
||||
private Boolean enabled;
|
||||
/// 最大在线时长(小时)
|
||||
private Integer maxOnlineHours;
|
||||
/// 最大活跃时长(小时), 0或null表示不限制
|
||||
private Integer activeTimeoutHours;
|
||||
/// 最大并发会话数
|
||||
private Integer maxConcurrentSessions;
|
||||
/// 并发会话策略
|
||||
|
||||
@@ -17,6 +17,9 @@ public class PlatformSessionManagementConfigParam {
|
||||
@Schema(description = "最大在线时长(小时)")
|
||||
private Integer maxOnlineHours;
|
||||
|
||||
@Schema(description = "最大活跃时长(小时),0或留空表示不限制")
|
||||
private Integer activeTimeoutHours;
|
||||
|
||||
@Schema(description = "最大并发会话数")
|
||||
private Integer maxConcurrentSessions;
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ public class PlatformSessionManagementConfigResult extends BaseResult {
|
||||
@Schema(description = "最大在线时长(小时)")
|
||||
private Integer maxOnlineHours;
|
||||
|
||||
@Schema(description = "最大活跃时长(小时),0或留空表示不限制")
|
||||
private Integer activeTimeoutHours;
|
||||
|
||||
@Schema(description = "最大并发会话数")
|
||||
private Integer maxConcurrentSessions;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user