发布 v1.10 #5
@@ -51,9 +51,10 @@ public final class AuthLoginSessionPolicy {
|
||||
/**
|
||||
* 判断 Web 登录是否需要替换既有 Web 会话。
|
||||
*
|
||||
* @return 始终为 true
|
||||
* @param multiLogin 是否允许账号多端登录
|
||||
* @return 禁止多端登录时返回 true
|
||||
*/
|
||||
public static boolean shouldReplaceExistingWebSession() {
|
||||
return true;
|
||||
public static boolean shouldReplaceExistingWebSession(boolean multiLogin) {
|
||||
return !multiLogin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,13 @@ import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.constant.enums.EnumDataStatus;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.system.entity.SysApiKey;
|
||||
import tech.easyflow.system.config.AccountSecurityProperties;
|
||||
import tech.easyflow.system.entity.SysAccount;
|
||||
import tech.easyflow.system.entity.SysApiKey;
|
||||
import tech.easyflow.system.entity.SysMenu;
|
||||
import tech.easyflow.system.entity.SysRole;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
import tech.easyflow.system.service.SysAccountService;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
import tech.easyflow.system.service.SysMenuService;
|
||||
import tech.easyflow.system.service.SysRoleService;
|
||||
import tech.easyflow.system.util.SysPasswordPolicy;
|
||||
@@ -54,6 +55,8 @@ public class AuthServiceImpl implements AuthService, StpInterface {
|
||||
private SysApiKeyService sysApiKeyService;
|
||||
@Resource
|
||||
private RedisLockExecutor redisLockExecutor;
|
||||
@Resource
|
||||
private AccountSecurityProperties accountSecurityProperties;
|
||||
|
||||
@Override
|
||||
public LoginVO login(LoginDTO loginDTO) {
|
||||
@@ -171,22 +174,23 @@ public class AuthServiceImpl implements AuthService, StpInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建互斥的 Web 登录会话。
|
||||
* 根据账号安全策略创建 Web 登录会话。
|
||||
*
|
||||
* @param record 登录账号
|
||||
* @return 登录结果
|
||||
*/
|
||||
private LoginVO createWebLoginVO(SysAccount record) {
|
||||
if (!AuthLoginSessionPolicy.shouldReplaceExistingWebSession(accountSecurityProperties.isMultiLogin())) {
|
||||
return createLoginVO(record, AuthLoginSessionPolicy.webLoginModel());
|
||||
}
|
||||
return redisLockExecutor.executeWithLock(
|
||||
WEB_LOGIN_LOCK_KEY_PREFIX + record.getId(),
|
||||
WEB_LOGIN_LOCK_WAIT,
|
||||
WEB_LOGIN_LOCK_LEASE,
|
||||
() -> {
|
||||
if (AuthLoginSessionPolicy.shouldReplaceExistingWebSession()) {
|
||||
StpUtil.replaced(record.getId(), AuthLoginSessionPolicy.WEB_DEVICE);
|
||||
// 首次升级后的新登录同时淘汰旧版本未标记设备类型的浏览器会话。
|
||||
StpUtil.replaced(record.getId(), AuthLoginSessionPolicy.LEGACY_WEB_DEVICE);
|
||||
}
|
||||
return createLoginVO(record, AuthLoginSessionPolicy.webLoginModel());
|
||||
}
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.junit.Test;
|
||||
public class AuthLoginSessionPolicyTest {
|
||||
|
||||
/**
|
||||
* 验证 Web 登录使用独立设备类型并要求替换旧会话。
|
||||
* 验证 Web 登录设备类型和多端登录会话替换策略。
|
||||
*/
|
||||
@Test
|
||||
public void shouldBuildExclusiveWebLoginModel() {
|
||||
@@ -18,7 +18,8 @@ public class AuthLoginSessionPolicyTest {
|
||||
|
||||
Assert.assertEquals("WEB", model.getDevice());
|
||||
Assert.assertEquals("default-device", AuthLoginSessionPolicy.LEGACY_WEB_DEVICE);
|
||||
Assert.assertTrue(AuthLoginSessionPolicy.shouldReplaceExistingWebSession());
|
||||
Assert.assertTrue(AuthLoginSessionPolicy.shouldReplaceExistingWebSession(false));
|
||||
Assert.assertFalse(AuthLoginSessionPolicy.shouldReplaceExistingWebSession(true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,11 @@ public class AccountSecurityProperties implements InitializingBean {
|
||||
*/
|
||||
private String defaultResetPassword = "!QAZ2wsx";
|
||||
|
||||
/**
|
||||
* 是否允许同一账号同时在多个客户端登录。
|
||||
*/
|
||||
private boolean multiLogin = false;
|
||||
|
||||
/**
|
||||
* 获取默认重置密码。
|
||||
*
|
||||
@@ -35,6 +40,24 @@ public class AccountSecurityProperties implements InitializingBean {
|
||||
this.defaultResetPassword = defaultResetPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否允许同一账号同时在多个客户端登录。
|
||||
*
|
||||
* @return 允许多端登录时返回 true
|
||||
*/
|
||||
public boolean isMultiLogin() {
|
||||
return multiLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否允许同一账号同时在多个客户端登录。
|
||||
*
|
||||
* @param multiLogin 是否允许多端登录
|
||||
*/
|
||||
public void setMultiLogin(boolean multiLogin) {
|
||||
this.multiLogin = multiLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用启动时校验默认密码符合系统强密码策略。
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,19 @@ public class AccountSecurityPropertiesTest {
|
||||
properties.afterPropertiesSet();
|
||||
|
||||
Assert.assertEquals("!QAZ2wsx", properties.getDefaultResetPassword());
|
||||
Assert.assertFalse(properties.isMultiLogin());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证账号多端登录配置可以开启。
|
||||
*/
|
||||
@Test
|
||||
public void shouldEnableAccountMultiLogin() {
|
||||
AccountSecurityProperties properties = new AccountSecurityProperties();
|
||||
|
||||
properties.setMultiLogin(true);
|
||||
|
||||
Assert.assertTrue(properties.isMultiLogin());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,7 +98,8 @@ easyflow:
|
||||
cron: "0 30 2 * * *"
|
||||
security:
|
||||
account:
|
||||
default-reset-password: '${EASYFLOW_DEFAULT_RESET_PASSWORD:!QAZ2wsx}'
|
||||
default-reset-password: "!QAZ2wsx"
|
||||
multi-login: false
|
||||
license:
|
||||
location: classpath:easyflow.lic
|
||||
chat:
|
||||
|
||||
Reference in New Issue
Block a user