From b428e2d4587b4260e9df78ba326e6562aaf15df9 Mon Sep 17 00:00:00 2001 From: huangrx22040601011 Date: Thu, 17 Sep 2026 16:19:48 +0800 Subject: [PATCH 1/2] [Improvement-18652][API] Make login session timeout configurable The session lifetime was a compile-time constant in the shared dolphinscheduler-common module, which forced a rebuild and a replacement of the jars consumed by master, worker and alert to change a setting that only concerns the API server. Being a static final int, it was also inlined into SessionServiceImpl, so editing the constant alone was not enough. Move it to ApiConfig as a Duration defaulting to 2h, keeping the existing behaviour when the property is unset, and expose it as api.session-timeout so operators can tune it from api-server/conf/application.yaml. Expiry semantics are unchanged: the timeout is still measured from the moment the user logs in. --- docs/docs/en/architecture/configuration.md | 1 + docs/docs/zh/architecture/configuration.md | 1 + .../api/configuration/ApiConfig.java | 10 ++++++++++ .../api/service/impl/SessionServiceImpl.java | 8 ++++++-- .../src/main/resources/application.yaml | 3 +++ .../api/controller/LoginControllerTest.java | 5 ++++- .../api/service/SessionServiceTest.java | 20 +++++++++++++++++++ .../common/constants/Constants.java | 2 -- .../src/main/resources/application.yaml | 3 +++ 9 files changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/docs/en/architecture/configuration.md b/docs/docs/en/architecture/configuration.md index 00b98c7356aa..cb37799a853e 100644 --- a/docs/docs/en/architecture/configuration.md +++ b/docs/docs/en/architecture/configuration.md @@ -260,6 +260,7 @@ Location: `api-server/conf/application.yaml` | casdoor.organization-name | | organization name in Casdoor | | casdoor.application-name | | application name in Casdoor | | casdoor.redirect-url | | doplhinscheduler login url | +| api.session-timeout | 2h | login session lifetime measured from login time; accepts a Duration (e.g. 30m, 12h, 1d) | | api.traffic.control.global.switch | false | traffic control global switch | | api.traffic.control.max-global-qps-rate | 300 | global max request number per second | | api.traffic.control.tenant-switch | false | traffic control tenant switch | diff --git a/docs/docs/zh/architecture/configuration.md b/docs/docs/zh/architecture/configuration.md index 335a9b1d2d07..bf735464550e 100644 --- a/docs/docs/zh/architecture/configuration.md +++ b/docs/docs/zh/architecture/configuration.md @@ -260,6 +260,7 @@ common.properties配置文件目前主要是配置hadoop/s3/yarn/applicationId | casdoor.organization-name | | Casdoor中的组织名称 | | casdoor.application-name | | Casdoor中的应用名称 | | casdoor.redirect-url | | dolphinscheduler登录URL | +| api.session-timeout | 2h | 登录会话有效期,从登录时刻开始计算,支持 Duration 格式(如 30m、12h、1d) | | api.traffic.control.global.switch | false | 流量控制全局开关 | | api.traffic.control.max-global-qps-rate | 300 | 全局最大请求数/秒 | | api.traffic.control.tenant-switch | false | 流量控制租户开关 | diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/configuration/ApiConfig.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/configuration/ApiConfig.java index 2ba09ee37b0d..ef5c49929f50 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/configuration/ApiConfig.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/configuration/ApiConfig.java @@ -19,6 +19,7 @@ import org.apache.commons.lang3.StringUtils; +import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -44,6 +45,7 @@ public class ApiConfig implements Validator { private String baseUrl; private String uiUrl; private boolean auditEnable = false; + private Duration sessionTimeout = Duration.ofHours(2); private TrafficConfiguration trafficControl = new TrafficConfiguration(); @@ -57,6 +59,7 @@ public boolean supports(Class clazz) { @Override public void validate(Object target, Errors errors) { validatePythonGateway(errors); + validateSessionTimeout(errors); printConfig(); } @@ -66,10 +69,17 @@ private void validatePythonGateway(Errors errors) { } } + private void validateSessionTimeout(Errors errors) { + if (sessionTimeout.isZero() || sessionTimeout.isNegative()) { + errors.rejectValue("sessionTimeout", null, "should be positive"); + } + } + private void printConfig() { log.info("API config: baseUrl -> {} ", baseUrl); log.info("API config: uiUrl -> {} ", uiUrl); log.info("API config: auditEnable -> {} ", auditEnable); + log.info("API config: sessionTimeout -> {} ", sessionTimeout); log.info("API config: trafficControl -> {} ", trafficControl); log.info("API config: pythonGateway -> {} ", pythonGateway); } diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SessionServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SessionServiceImpl.java index a3571eb19e2d..b476fd1db6f3 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SessionServiceImpl.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SessionServiceImpl.java @@ -17,8 +17,8 @@ package org.apache.dolphinscheduler.api.service.impl; +import org.apache.dolphinscheduler.api.configuration.ApiConfig; import org.apache.dolphinscheduler.api.service.SessionService; -import org.apache.dolphinscheduler.common.constants.Constants; import org.apache.dolphinscheduler.dao.entity.Session; import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.repository.SessionDao; @@ -46,6 +46,9 @@ public class SessionServiceImpl extends BaseServiceImpl implements SessionServic @Autowired private SessionDao sessionDao; + @Autowired + private ApiConfig apiConfig; + @Override public Session getSession(String sessionId) { if (StringUtils.isBlank(sessionId)) { @@ -94,7 +97,8 @@ public void expireSession(Integer userId) { @Override public boolean isSessionExpire(Session session) { - return System.currentTimeMillis() - session.getLastLoginTime().getTime() >= Constants.SESSION_TIME_OUT * 1000; + return System.currentTimeMillis() - session.getLastLoginTime().getTime() >= apiConfig.getSessionTimeout() + .toMillis(); } } diff --git a/dolphinscheduler-api/src/main/resources/application.yaml b/dolphinscheduler-api/src/main/resources/application.yaml index 9d3bb1c6a57a..58f9017f8b81 100644 --- a/dolphinscheduler-api/src/main/resources/application.yaml +++ b/dolphinscheduler-api/src/main/resources/application.yaml @@ -142,6 +142,9 @@ api: base-url: http://127.0.0.1:12345/dolphinscheduler ui-url: http://127.0.0.1:5173 audit-enable: false + # The lifetime of a login session, measured from the moment the user logs in. + # Accepts a Duration, e.g. 30m, 12h, 1d. Defaults to 2h when unset. + session-timeout: 2h # Traffic control, if you turn on this config, the maximum number of request/s will be limited. # global max request number per second # default tenant-level max request number diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java index 57fb1076df58..5f072084001f 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java @@ -82,6 +82,9 @@ public class LoginControllerTest extends AbstractControllerTest { @Autowired private SessionDao sessionDao; + @Autowired + private ApiConfig apiConfig; + @Test public void testLogin() throws Exception { MultiValueMap paramsMap = new LinkedMultiValueMap<>(); @@ -143,7 +146,7 @@ public void testSignOut() throws Exception { @Test void testSignOutWithExpireSession() throws Exception { final Session session = sessionDao.queryById(sessionId); - session.setLastLoginTime(new Date(System.currentTimeMillis() - Constants.SESSION_TIME_OUT * 1000 - 1)); + session.setLastLoginTime(new Date(System.currentTimeMillis() - apiConfig.getSessionTimeout().toMillis() - 1)); sessionDao.updateById(session); mockMvc.perform(post("/signOut") diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SessionServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SessionServiceTest.java index 6023e218dd96..659900306956 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SessionServiceTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SessionServiceTest.java @@ -17,6 +17,7 @@ package org.apache.dolphinscheduler.api.service; +import org.apache.dolphinscheduler.api.configuration.ApiConfig; import org.apache.dolphinscheduler.api.service.impl.SessionServiceImpl; import org.apache.dolphinscheduler.common.enums.UserType; import org.apache.dolphinscheduler.common.utils.DateUtils; @@ -24,6 +25,7 @@ import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.repository.SessionDao; +import java.time.Duration; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -37,6 +39,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) @@ -48,10 +51,14 @@ public class SessionServiceTest { @Mock private SessionDao sessionDao; + @Spy + private ApiConfig apiConfig = new ApiConfig(); + private String sessionId = "aaaaaaaaaaaaaaaaaa"; @BeforeEach public void setUp() { + apiConfig.setSessionTimeout(Duration.ofHours(2)); } @AfterEach @@ -100,6 +107,19 @@ public void testExpireSession() { } + @Test + public void testIsSessionExpireUsesConfiguredTimeout() { + apiConfig.setSessionTimeout(Duration.ofHours(1)); + + Session stillAlive = getSession(); + stillAlive.setLastLoginTime(new Date(System.currentTimeMillis() - Duration.ofMinutes(30).toMillis())); + Assertions.assertFalse(sessionService.isSessionExpire(stillAlive)); + + Session expired = getSession(); + expired.setLastLoginTime(new Date(System.currentTimeMillis() - Duration.ofMinutes(90).toMillis())); + Assertions.assertTrue(sessionService.isSessionExpire(expired)); + } + private Session getSession() { Session session = new Session(); session.setId(sessionId); diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/Constants.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/Constants.java index 499ed0cd5cf5..81783ed28528 100644 --- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/Constants.java +++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/Constants.java @@ -248,8 +248,6 @@ public final class Constants { */ public static final String LOCALE_LANGUAGE = "language"; - public static final int SESSION_TIME_OUT = 7200; - public static final int AUTHORIZE_WRITABLE_PERM = 7; public static final String START_TIME = "start time"; diff --git a/dolphinscheduler-standalone-server/src/main/resources/application.yaml b/dolphinscheduler-standalone-server/src/main/resources/application.yaml index bd13f0632185..74bafeffbd6d 100644 --- a/dolphinscheduler-standalone-server/src/main/resources/application.yaml +++ b/dolphinscheduler-standalone-server/src/main/resources/application.yaml @@ -260,6 +260,9 @@ alert: api: audit-enable: false + # The lifetime of a login session, measured from the moment the user logs in. + # Accepts a Duration, e.g. 30m, 12h, 1d. Defaults to 2h when unset. + session-timeout: 2h # Traffic control, if you turn on this config, the maximum number of request/s will be limited. # global max request number per second # default tenant-level max request number From 8450c3d189cb26014d1be7927627004fd3befb48 Mon Sep 17 00:00:00 2001 From: huangrx22040601011 Date: Sun, 20 Sep 2026 11:26:39 +0800 Subject: [PATCH 2/2] [Improvement-18652][Doc] Fix markdown table alignment in session timeout docs The Chinese configuration table row added for api.session-timeout was not padded to the flexmark-computed column width, so spotless:check failed and took the Docs, Backend-Build and Build CI jobs down with it. --- docs/docs/zh/architecture/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/zh/architecture/configuration.md b/docs/docs/zh/architecture/configuration.md index bf735464550e..a2b94379555b 100644 --- a/docs/docs/zh/architecture/configuration.md +++ b/docs/docs/zh/architecture/configuration.md @@ -260,7 +260,7 @@ common.properties配置文件目前主要是配置hadoop/s3/yarn/applicationId | casdoor.organization-name | | Casdoor中的组织名称 | | casdoor.application-name | | Casdoor中的应用名称 | | casdoor.redirect-url | | dolphinscheduler登录URL | -| api.session-timeout | 2h | 登录会话有效期,从登录时刻开始计算,支持 Duration 格式(如 30m、12h、1d) | +| api.session-timeout | 2h | 登录会话有效期,从登录时刻开始计算,支持 Duration 格式(如 30m、12h、1d) | | api.traffic.control.global.switch | false | 流量控制全局开关 | | api.traffic.control.max-global-qps-rate | 300 | 全局最大请求数/秒 | | api.traffic.control.tenant-switch | false | 流量控制租户开关 |