yyqdbngt opened a new pull request, #5325:
URL: https://github.com/apache/rocketmq-dashboard/pull/5325
### Which Issue(s) This PR Fixes
- Fixes #5303
### Brief Description
A Studio session token stayed valid until its **absolute** expiry — 24 hours
by default — no matter how long it went unused. The console already tracked and
displayed inactivity: `last_seen_at` is written on authenticated requests,
refreshed at most once per 5 minutes (`LAST_SEEN_UPDATE_INTERVAL`), classified
as "长时间未活跃" after 15 minutes (`STALE_SESSION_THRESHOLD`) and reported as a
stale-session count on the overview — but the token validation path in
`AuthService` checked revocation and absolute expiry only, so a stale session
stayed fully authenticated. A token copied from an abandoned browser or a
shared workstation kept working for a day with zero activity required.
This change adds an idle deadline:
- `AuthProperties.sessionIdleTimeoutMinutes`
(`studio.auth.session-idle-timeout-minutes`, env
`STUDIO_AUTH_SESSION_IDLE_TIMEOUT_MINUTES`), default **30 minutes**, next to
the other `studio.auth.*` deployment settings.
- `AuthService.databaseUserForToken` rejects a session whose last use is
older than the window **and** writes `revoked_at = now` on the row, so the
session drawer and the overview counters stop counting a token nobody can use
any more.
- The existing five-minute `@Scheduled` session cleanup
(`purgeExpiredSessions`) revokes idle-expired rows as well, so an abandoned
token that is never presented again still disappears from the active-session
views; rows are still deleted at absolute expiry exactly as before.
- The in-memory (properties-based) mode tracks last-seen per token and
enforces the same window, through token presentation and through its cleanup.
- `0` is the explicit opt-out (absolute expiry only). Values 1–9 resolve to
**10** minutes — deliberately above the 5-minute last-seen write throttle, so
an active session's throttled writes can never lag enough to idle it out
falsely. Values above 1440 fall back to the default, mirroring the absolute
timeout's defensive clamp. Sessions written before `last_seen_at` existed
(NULL) keep the absolute deadline as their only deadline. The absolute session
timeout and the login flow are unchanged.
The idle window is configured as a deployment property rather than as a
field on the general-settings page: the enforcement, the opt-out and the
scheduled revocation are this PR, and a settings-page field would ride on top
of the same value.
One existing assertion had to be narrowed for the new scheduled statement:
`AuthServicePasswordChangeIntegrationTest` counted *every*
`sessionMapper.update` call on its mocked mapper, and that same mapper is now
also written once per sweep by `revokeIdleSessions`. Both verifications in that
class now pin the statement they are actually about (`... contains("user_id")`)
instead of counting all updates; no behavioural expectation changed.
### How Did You Test This Change?
`AuthServiceIdleTimeoutTest` (new, mocks the session/user mappers and the
settings repository, fixed clock at `2026-08-13T12:00:00Z`) asserts: a token
unused for 60 minutes with an absolute expiry still in the future is rejected
*and* its row is revoked; a token used 10 minutes ago stays authenticated and
refreshes `last_seen_at`; a token inside the 5-minute write throttle is neither
rewritten nor revoked; idle window 0 leaves a 6-hour-idle token authenticated;
window 1 resolves to 10 minutes (7 minutes idle stays authenticated, 11 minutes
is revoked); a session without `last_seen_at` keeps the absolute deadline; the
scheduled cleanup revokes rows whose `last_seen_at` is older than 30 minutes
with the same `revoked_at IS NULL AND expires_at > now` predicate the per-user
revoke uses, and still deletes absolutely-expired rows; and both in-memory
paths (presentation and cleanup) drop an idle token.
```powershell
$ cd server && mvn -B -ntp test -Dtest=AuthServiceIdleTimeoutTest
[ERROR] Tests run: 9, Failures: 6, Errors: 0, Skipped: 0 <- before the fix
[INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0 <- after the fix
[INFO] BUILD SUCCESS
```
Raw red run (before the change):
```
[ERROR] Tests run: 9, Failures: 6, Errors: 0, Skipped: 0, Time elapsed:
2.579 s <<< FAILURE! -- in
org.apache.rocketmq.studio.auth.AuthServiceIdleTimeoutTest
Expecting value to be false but was true
Expecting empty but was:
{"studio-jwt-9bfe9449-e5fd-4fbb-821a-2002d80f9003"=AuthSession[user=LoginVO.UserInfo(userId=null,
username=operator, admin=false), expiresAtMillis=1786708800000]}
Wanted but not invoked:
Expecting an empty Optional but was containing value:
LoginVO.UserInfo(userId=1, username=operator, admin=false)
[ERROR]
AuthServiceIdleTimeoutTest.anIdleWindowBelowTheLastSeenThrottleResolvesToTheMinimumOfTenMinutes:122->configureIdleTimeoutMinutes:238
AuthProperties has no session idle timeout setting
[ERROR]
AuthServiceIdleTimeoutTest.idleTimeoutZeroLeavesTheAbsoluteTimeoutAsTheOnlyDeadline:112->configureIdleTimeoutMinutes:238
AuthProperties has no session idle timeout setting
[ERROR]
AuthServiceIdleTimeoutTest.inMemoryCleanupDropsTokensThatIdledOut:191
Expecting empty but was:
{"studio-jwt-9bfe9449-e5fd-4fbb-821a-2002d80f9003"=AuthSession[user=LoginVO.UserInfo(userId=null,
username=operator, admin=false), expiresAtMillis=1786708800000]}
[ERROR]
AuthServiceIdleTimeoutTest.inMemorySessionsAlsoExpireOnceTheirTokenStaysIdle:176
Expecting value to be false but was true
[ERROR]
AuthServiceIdleTimeoutTest.scheduledCleanupRevokesIdleSessionsAndStillDeletesAbsolutelyExpiredRows:154->theOnlySessionUpdate:222
Wanted but not invoked:
[ERROR]
AuthServiceIdleTimeoutTest.tokenUnusedBeyondTheIdleWindowIsRejectedAndRevokedBeforeItsAbsoluteExpiry:85
Expecting an empty Optional but was containing value:
LoginVO.UserInfo(userId=1, username=operator, admin=false)
[ERROR] Tests run: 9, Failures: 6, Errors: 0, Skipped: 0
[INFO] BUILD FAILURE
```
Green run after the change (same test file):
```powershell
$ cd server && mvn -B -ntp test -Dtest=AuthServiceIdleTimeoutTest
[INFO] You have 0 Checkstyle violations.
[INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
The full server suite was also run to check for regressions in the sessions
that were already green:
```powershell
$ cd server && mvn -B -ntp test
[INFO] Tests run: 3331, Failures: 8, Errors: 27, Skipped: 4
```
(3331 = the 3322 tests of the base revision plus the 9 new ones; the 8
failures and 27 errors are the pre-existing MySQL-8 / external-CLI classes.)
### Checklist
- [x] One coherent change; unrelated modifications are not bundled in
- [x] Commit subject follows Conventional Commits
- [x] Tests added or updated for non-trivial changes
- [ ] New UI text has both Chinese and English entries under `web/src/i18n/`
— does not apply, this change adds no UI text
- [ ] Architecture constraints stay green — no ArchUnit rule class exists in
the repository and this change adds none; the maven runs above report 0
checkstyle violations
- [x] New source files carry the ASF license header
- [ ] Documentation touched where behaviour changed — not ticked: the new
property is documented by the `AuthProperties` javadoc;
`server/src/main/resources/application.yml` is outside the file set this change
was scoped to, so no `studio.auth.session-idle-timeout-minutes` entry was added
there
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]