Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0d03adbe1 | ||
|
|
b229103d8c | ||
|
|
94b441c676 | ||
|
|
b2f10c6752 | ||
|
|
b3d228eb2e | ||
|
|
19dd3d8be1 | ||
|
|
1aaffb28fc | ||
|
|
75af61ca6c | ||
|
|
2fff593423 | ||
|
|
6a381d3226 | ||
|
|
cd628fe5af | ||
|
|
ee4df64bb1 | ||
|
|
d850762bce | ||
|
|
f71d1d6ca4 | ||
|
|
e5eeacec5f | ||
|
|
62ec64310b | ||
|
|
25d810eaa3 | ||
|
|
82db55c3f8 | ||
|
|
1f38a937bd | ||
|
|
e027d2091b | ||
|
|
bcbe53c3dd | ||
|
|
72742b52e3 | ||
|
|
1889a4c64e | ||
|
|
3000f3198f | ||
|
|
82a12afe93 | ||
|
|
d2da662c3f | ||
|
|
95e2c9e42a | ||
|
|
ff8672b1d5 | ||
|
|
31d4a766eb | ||
|
|
ce332022de | ||
|
|
5c2ca6d5ac | ||
|
|
bc93d80a17 | ||
|
|
fd835fd316 | ||
|
|
4e3ea616ba | ||
|
|
08654749ae | ||
|
|
88306d037d | ||
|
|
de32e4c501 | ||
|
|
668f85788a | ||
|
|
fc81049cbe | ||
|
|
fbb94b40e8 | ||
|
|
009cb5b592 | ||
|
|
525b841ad6 | ||
|
|
185ea87ff4 | ||
|
|
aebe5ece6f | ||
|
|
30b8e68c67 | ||
|
|
c2f8428df9 | ||
|
|
b5197b8665 | ||
|
|
2406ec8302 | ||
|
|
6d74cf5f35 | ||
|
|
da8e5fbbac | ||
|
|
4b34f35b82 | ||
|
|
954a40f5d1 | ||
|
|
fb66cf3150 | ||
|
|
a23090e7e5 | ||
|
|
beaca53d44 | ||
|
|
baed403a6a | ||
|
|
cd51c36dc0 |
9
.gitattributes
vendored
Normal file
9
.gitattributes
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
* text eol=lf
|
||||
|
||||
*.bat text eol=crlf
|
||||
|
||||
*.jar binary
|
||||
|
||||
*.png binary
|
||||
|
||||
*.mmdb binary
|
||||
@@ -1,3 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
org.gradle.parallel=true
|
||||
version=3.0.0-M4
|
||||
version=3.0.0-RC2
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'io.projectreactor:reactor-bom:2022.0.0-M6'
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.4'
|
||||
mavenBom 'org.junit:junit-bom:5.9.0'
|
||||
mavenBom 'org.mockito:mockito-bom:4.8.0'
|
||||
mavenBom 'org.springframework:spring-framework-bom:6.0.0-M6'
|
||||
mavenBom 'org.springframework.data:spring-data-bom:2022.0.0-M6'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:6.0.0-M7'
|
||||
mavenBom 'io.projectreactor:reactor-bom:2022.0.0'
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.4.20221013'
|
||||
mavenBom 'org.junit:junit-bom:5.9.1'
|
||||
mavenBom 'org.mockito:mockito-bom:4.8.1'
|
||||
mavenBom 'org.springframework:spring-framework-bom:6.0.0-RC4'
|
||||
mavenBom 'org.springframework.data:spring-data-bom:2022.0.0-RC2'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:6.0.0-RC2'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.17.3'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependency 'com.hazelcast:hazelcast:5.1.3'
|
||||
dependency 'com.hazelcast:hazelcast:5.1.4'
|
||||
dependency 'org.aspectj:aspectjweaver:1.9.9.1'
|
||||
dependency 'ch.qos.logback:logback-core:1.2.11'
|
||||
dependency 'ch.qos.logback:logback-core:1.4.4'
|
||||
dependency 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
dependency 'com.h2database:h2:2.1.214'
|
||||
dependency 'com.ibm.db2:jcc:11.5.7.0'
|
||||
@@ -21,16 +21,20 @@ dependencyManagement {
|
||||
dependency 'com.oracle.database.jdbc:ojdbc8:21.7.0.0'
|
||||
dependency 'com.zaxxer:HikariCP:5.0.1'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:6.2.0.RELEASE'
|
||||
dependency 'jakarta.annotation:jakarta.annotation-api:2.0.0'
|
||||
dependency 'jakarta.servlet:jakarta.servlet-api:5.0.0'
|
||||
dependency 'io.lettuce:lettuce-core:6.2.1.RELEASE'
|
||||
dependency 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
||||
dependency 'jakarta.websocket:jakarta.websocket-api:2.1.0'
|
||||
dependency 'jakarta.websocket:jakarta.websocket-client-api:2.1.0'
|
||||
dependency 'mysql:mysql-connector-java:8.0.30'
|
||||
dependency 'org.apache.derby:derby:10.14.2.0'
|
||||
dependencySet(group: 'org.apache.derby', version: '10.16.1.1') {
|
||||
entry 'derby'
|
||||
entry 'derbytools'
|
||||
}
|
||||
dependency 'org.assertj:assertj-core:3.23.1'
|
||||
dependency 'org.hamcrest:hamcrest:2.2'
|
||||
dependency 'org.hsqldb:hsqldb:2.7.0'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:3.0.7'
|
||||
dependencySet(group: 'org.mongodb', version: '4.7.1') {
|
||||
dependencySet(group: 'org.mongodb', version: '4.8.0-beta0') {
|
||||
entry 'mongodb-driver-core'
|
||||
entry 'mongodb-driver-sync'
|
||||
entry 'mongodb-driver-reactivestreams'
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
6
gradlew
vendored
6
gradlew
vendored
@@ -205,6 +205,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
||||
180
gradlew.bat
vendored
180
gradlew.bat
vendored
@@ -1,89 +1,91 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
@@ -6,12 +6,13 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.9"
|
||||
id "com.gradle.enterprise" version "3.11.2"
|
||||
id "io.spring.ge.conventions" version "0.0.7"
|
||||
}
|
||||
|
||||
rootProject.name = 'spring-session-build'
|
||||
|
||||
include 'spring-session-bom'
|
||||
include 'spring-session-core'
|
||||
include 'spring-session-data-mongodb'
|
||||
include 'spring-session-data-redis'
|
||||
|
||||
15
spring-session-bom/spring-session-bom.gradle
Normal file
15
spring-session-bom/spring-session-bom.gradle
Normal file
@@ -0,0 +1,15 @@
|
||||
import io.spring.gradle.convention.SpringModulePlugin
|
||||
|
||||
plugins {
|
||||
id("io.spring.convention.bom")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
constraints {
|
||||
project.rootProject.allprojects { project ->
|
||||
project.plugins.withType(SpringModulePlugin) {
|
||||
api(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ dependencies {
|
||||
api "org.springframework:spring-jcl"
|
||||
|
||||
optional "io.projectreactor:reactor-core"
|
||||
optional "jakarta.annotation:jakarta.annotation-api"
|
||||
optional "jakarta.servlet:jakarta.servlet-api"
|
||||
optional "org.springframework:spring-context"
|
||||
optional "org.springframework:spring-jdbc"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,10 +49,16 @@ import java.util.UUID;
|
||||
public final class MapSession implements Session, Serializable {
|
||||
|
||||
/**
|
||||
* Default {@link #setMaxInactiveInterval(Duration)} (30 minutes).
|
||||
* Default {@link #setMaxInactiveInterval(Duration)} (30 minutes) in seconds.
|
||||
*/
|
||||
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
|
||||
|
||||
/**
|
||||
* Default {@link #setMaxInactiveInterval(Duration)} (30 minutes).
|
||||
*/
|
||||
public static final Duration DEFAULT_MAX_INACTIVE_INTERVAL = Duration
|
||||
.ofSeconds(DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private String id;
|
||||
|
||||
private final String originalId;
|
||||
@@ -66,7 +72,7 @@ public final class MapSession implements Session, Serializable {
|
||||
/**
|
||||
* Defaults to 30 minutes.
|
||||
*/
|
||||
private Duration maxInactiveInterval = Duration.ofSeconds(DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
private Duration maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
/**
|
||||
* Creates a new instance with a secure randomly generated identifier.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link SessionRepository} backed by a {@link java.util.Map} and that uses a
|
||||
@@ -38,11 +39,7 @@ import org.springframework.session.events.SessionExpiredEvent;
|
||||
*/
|
||||
public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private final Map<String, Session> sessions;
|
||||
|
||||
@@ -59,12 +56,13 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
|
||||
* should be kept alive between client requests.
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
@@ -97,9 +95,7 @@ public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
@Override
|
||||
public MapSession createSession() {
|
||||
MapSession result = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
result.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ReactiveSessionRepository} backed by a {@link Map} and that uses a
|
||||
@@ -40,11 +41,7 @@ import org.springframework.session.events.SessionExpiredEvent;
|
||||
*/
|
||||
public class ReactiveMapSessionRepository implements ReactiveSessionRepository<MapSession> {
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private final Map<String, Session> sessions;
|
||||
|
||||
@@ -61,12 +58,13 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
|
||||
* should be kept alive between client requests.
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
@@ -99,9 +97,7 @@ public class ReactiveMapSessionRepository implements ReactiveSessionRepository<M
|
||||
public Mono<MapSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
MapSession result = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
result.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
return Mono.just(result);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
@@ -34,7 +33,7 @@ import org.springframework.session.events.SessionDestroyedEvent;
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @Configuration}
|
||||
* {@literal @Configuration(proxyBeanMethods = false)}
|
||||
* {@literal @EnableSpringHttpSession}
|
||||
* public class SpringHttpSessionConfig {
|
||||
*
|
||||
@@ -74,7 +73,6 @@ import org.springframework.session.events.SessionDestroyedEvent;
|
||||
@Target({ java.lang.annotation.ElementType.TYPE })
|
||||
@Documented
|
||||
@Import(SpringHttpSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableSpringHttpSession {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.session.config.annotation.web.http;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.SessionCookieConfig;
|
||||
import jakarta.servlet.http.HttpSessionListener;
|
||||
@@ -28,6 +27,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -91,7 +91,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* @see EnableSpringHttpSession
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
public class SpringHttpSessionConfiguration implements InitializingBean, ApplicationContextAware {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -107,8 +107,8 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
|
||||
private List<HttpSessionListener> httpSessionListeners = new ArrayList<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
CookieSerializer cookieSerializer = (this.cookieSerializer != null) ? this.cookieSerializer
|
||||
: createDefaultCookieSerializer();
|
||||
this.defaultHttpSessionIdResolver.setCookieSerializer(cookieSerializer);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
@@ -31,7 +30,7 @@ import org.springframework.context.annotation.Import;
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @Configuration}
|
||||
* {@literal @Configuration(proxyBeanMethods = false)}
|
||||
* {@literal @EnableSpringWebSession}
|
||||
* public class SpringWebFluxConfig {
|
||||
*
|
||||
@@ -50,7 +49,6 @@ import org.springframework.context.annotation.Import;
|
||||
@Target({ java.lang.annotation.ElementType.TYPE })
|
||||
@Documented
|
||||
@Import(SpringWebSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableSpringWebSession {
|
||||
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ public class HeaderHttpSessionIdResolver implements HttpSessionIdResolver {
|
||||
@Override
|
||||
public List<String> resolveSessionIds(HttpServletRequest request) {
|
||||
String headerValue = request.getHeader(this.headerName);
|
||||
System.out.println(headerValue);
|
||||
return (headerValue != null) ? Collections.singletonList(headerValue) : Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,14 +19,11 @@ package org.springframework.session.web.http;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.servlet.http.HttpSessionBindingEvent;
|
||||
import jakarta.servlet.http.HttpSessionBindingListener;
|
||||
import jakarta.servlet.http.HttpSessionContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -41,7 +38,6 @@ import org.springframework.session.Session;
|
||||
* @author Vedran Pavic
|
||||
* @since 1.1
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);
|
||||
@@ -101,35 +97,18 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
return (int) this.session.getMaxInactiveInterval().getSeconds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSessionContext getSessionContext() {
|
||||
return NOOP_SESSION_CONTEXT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
checkState();
|
||||
return this.session.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(String name) {
|
||||
return getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
checkState();
|
||||
return Collections.enumeration(this.session.getAttributeNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getValueNames() {
|
||||
checkState();
|
||||
Set<String> attrs = this.session.getAttributeNames();
|
||||
return attrs.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
checkState();
|
||||
@@ -156,11 +135,6 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putValue(String name, Object value) {
|
||||
setAttribute(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
checkState();
|
||||
@@ -176,11 +150,6 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValue(String name) {
|
||||
removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
checkState();
|
||||
@@ -203,32 +172,4 @@ class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
}
|
||||
}
|
||||
|
||||
private static final HttpSessionContext NOOP_SESSION_CONTEXT = new HttpSessionContext() {
|
||||
|
||||
@Override
|
||||
public HttpSession getSession(String sessionId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getIds() {
|
||||
return EMPTY_ENUMERATION;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private static final Enumeration<String> EMPTY_ENUMERATION = new Enumeration<String>() {
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nextElement() {
|
||||
throw new NoSuchElementException("a");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -75,6 +75,7 @@ import org.springframework.session.SessionRepository;
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
* @author Josh Cummings
|
||||
* @author Yanming Zhou
|
||||
* @since 1.0
|
||||
*/
|
||||
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
|
||||
@@ -222,10 +223,11 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
}
|
||||
else {
|
||||
S session = wrappedSession.getSession();
|
||||
String requestedSessionId = getRequestedSessionId();
|
||||
clearRequestedSessionCache();
|
||||
SessionRepositoryFilter.this.sessionRepository.save(session);
|
||||
String sessionId = session.getId();
|
||||
if (!isRequestedSessionIdValid() || !sessionId.equals(getRequestedSessionId())) {
|
||||
if (!isRequestedSessionIdValid() || !sessionId.equals(requestedSessionId)) {
|
||||
SessionRepositoryFilter.this.httpSessionIdResolver.setSessionId(this, this.response, sessionId);
|
||||
}
|
||||
}
|
||||
@@ -265,14 +267,7 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
if (requestedSession != null) {
|
||||
requestedSession.setLastAccessedTime(Instant.now());
|
||||
}
|
||||
return isRequestedSessionIdValid(requestedSession);
|
||||
}
|
||||
return this.requestedSessionIdValid;
|
||||
}
|
||||
|
||||
private boolean isRequestedSessionIdValid(S session) {
|
||||
if (this.requestedSessionIdValid == null) {
|
||||
this.requestedSessionIdValid = session != null;
|
||||
this.requestedSessionIdValid = (requestedSession != null);
|
||||
}
|
||||
return this.requestedSessionIdValid;
|
||||
}
|
||||
@@ -356,7 +351,6 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
S session = SessionRepositoryFilter.this.sessionRepository.findById(sessionId);
|
||||
if (session != null) {
|
||||
this.requestedSession = session;
|
||||
this.requestedSessionId = sessionId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,8 +60,8 @@ class MapSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
void createSessionCustomDefaultExpiration() {
|
||||
final Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
|
||||
this.repository.setDefaultMaxInactiveInterval((int) expectedMaxInterval.getSeconds());
|
||||
Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
|
||||
this.repository.setDefaultMaxInactiveInterval(expectedMaxInterval);
|
||||
|
||||
Session session = this.repository.createSession();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -103,8 +103,8 @@ class ReactiveMapSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
void createSessionWhenCustomMaxInactiveIntervalThenCustomMaxInactiveInterval() {
|
||||
final Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
|
||||
this.repository.setDefaultMaxInactiveInterval((int) expectedMaxInterval.getSeconds());
|
||||
Duration expectedMaxInterval = new MapSession().getMaxInactiveInterval().plusSeconds(10);
|
||||
this.repository.setDefaultMaxInactiveInterval(expectedMaxInterval);
|
||||
|
||||
Session session = this.repository.createSession().block();
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class WebSessionSecurityRuntimeHintsTests {
|
||||
classUtilsMock.when(() -> ClassUtils.isPresent(eq("org.springframework.web.server.WebSession"), any()))
|
||||
.thenReturn(false);
|
||||
this.webSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
|
||||
assertThat(this.hints.serialization().javaSerialization()).isEmpty();
|
||||
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class WebSessionSecurityRuntimeHintsTests {
|
||||
.isPresent(eq("org.springframework.security.web.server.csrf.DefaultCsrfToken"), any()))
|
||||
.thenReturn(false);
|
||||
this.webSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
|
||||
assertThat(this.hints.serialization().javaSerialization()).isEmpty();
|
||||
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class HttpSessionSecurityRuntimeHintsTests {
|
||||
classUtilsMock.when(() -> ClassUtils.isPresent(eq("jakarta.servlet.http.HttpSession"), any()))
|
||||
.thenReturn(false);
|
||||
this.httpSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
|
||||
assertThat(this.hints.serialization().javaSerialization()).isEmpty();
|
||||
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class HttpSessionSecurityRuntimeHintsTests {
|
||||
() -> ClassUtils.isPresent(eq("org.springframework.security.web.csrf.DefaultCsrfToken"), any()))
|
||||
.thenReturn(false);
|
||||
this.httpSessionSecurityRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
|
||||
assertThat(this.hints.serialization().javaSerialization()).isEmpty();
|
||||
assertThat(this.hints.serialization().javaSerializationHints()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.ReactiveMapSessionRepository;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
@@ -105,6 +106,7 @@ class SpringWebSessionConfigurationTests {
|
||||
/**
|
||||
* A configuration with all the right parts.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableSpringWebSession
|
||||
static class GoodConfig {
|
||||
|
||||
@@ -122,11 +124,13 @@ class SpringWebSessionConfigurationTests {
|
||||
/**
|
||||
* A configuration where no {@link ReactiveSessionRepository} is defined. It's BAD!
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableSpringWebSession
|
||||
static class BadConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableSpringWebSession
|
||||
static class OverrideSessionIdResolver {
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -40,7 +39,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.servlet.http.HttpSessionBindingEvent;
|
||||
import jakarta.servlet.http.HttpSessionBindingListener;
|
||||
import jakarta.servlet.http.HttpSessionContext;
|
||||
|
||||
import org.assertj.core.data.Offset;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -316,52 +314,6 @@ class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterValue() throws Exception {
|
||||
final String ATTR = "ATTR";
|
||||
final String VALUE = "VALUE";
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
wrappedRequest.getSession().putValue(ATTR, VALUE);
|
||||
assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE);
|
||||
assertThat(Arrays.asList(wrappedRequest.getSession().getValueNames())).containsOnly(ATTR);
|
||||
}
|
||||
});
|
||||
|
||||
nextRequest();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE);
|
||||
assertThat(Arrays.asList(wrappedRequest.getSession().getValueNames())).containsOnly(ATTR);
|
||||
}
|
||||
});
|
||||
|
||||
nextRequest();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE);
|
||||
|
||||
wrappedRequest.getSession().removeValue(ATTR);
|
||||
|
||||
assertThat(wrappedRequest.getSession().getValue(ATTR)).isNull();
|
||||
}
|
||||
});
|
||||
|
||||
nextRequest();
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
assertThat(wrappedRequest.getSession().getValue(ATTR)).isNull();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterIsNewTrue() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@@ -637,27 +589,6 @@ class SessionRepositoryFilterTests {
|
||||
assertThat(session.getSecure()).describedAs("Session Cookie should be marked as Secure").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterSessionContext() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSessionContext sessionContext = wrappedRequest.getSession().getSessionContext();
|
||||
assertThat(sessionContext).isNotNull();
|
||||
assertThat(sessionContext.getSession("a")).isNull();
|
||||
assertThat(sessionContext.getIds()).isNotNull();
|
||||
assertThat(sessionContext.getIds().hasMoreElements()).isFalse();
|
||||
|
||||
try {
|
||||
sessionContext.getIds().nextElement();
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (NoSuchElementException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- saving
|
||||
|
||||
@Test
|
||||
@@ -741,23 +672,6 @@ class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateValueIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.invalidate();
|
||||
try {
|
||||
session.getValue("attr");
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (IllegalStateException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateAttributeNamesIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@@ -775,23 +689,6 @@ class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateValueNamesIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.invalidate();
|
||||
try {
|
||||
session.getValueNames();
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (IllegalStateException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateSetAttributeIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@@ -809,23 +706,6 @@ class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidatePutValueIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.invalidate();
|
||||
try {
|
||||
session.putValue("a", "b");
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (IllegalStateException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateRemoveAttributeIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@@ -843,23 +723,6 @@ class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateRemoveValueIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.invalidate();
|
||||
try {
|
||||
session.removeValue("name");
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (IllegalStateException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateNewIllegalState() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@@ -921,20 +784,6 @@ class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateSessionContext() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.invalidate();
|
||||
|
||||
// no exception
|
||||
session.getSessionContext();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterInvalidateMaxInteractiveInterval() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@@ -1327,8 +1176,8 @@ class SessionRepositoryFilterTests {
|
||||
}
|
||||
});
|
||||
|
||||
// 3 invocations expected: initial resolution, after invalidation, after commit
|
||||
verify(sessionRepository, times(3)).findById(eq(session.getId()));
|
||||
// 2 invocations expected: initial resolution, after invalidation
|
||||
verify(sessionRepository, times(2)).findById(eq(session.getId()));
|
||||
verify(sessionRepository).deleteById(eq(session.getId()));
|
||||
verify(sessionRepository).createSession();
|
||||
verify(sessionRepository).save(any());
|
||||
|
||||
@@ -18,6 +18,8 @@ dependencies {
|
||||
optional "org.mongodb:mongodb-driver-core"
|
||||
testImplementation "org.mongodb:mongodb-driver-sync"
|
||||
testImplementation "org.mongodb:mongodb-driver-reactivestreams"
|
||||
testImplementation 'jakarta.websocket:jakarta.websocket-api'
|
||||
testImplementation 'jakarta.websocket:jakarta.websocket-client-api'
|
||||
integrationTestCompile "org.testcontainers:mongodb"
|
||||
|
||||
// Everything else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@@ -25,9 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.serializer.DefaultDeserializer;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.Assert;
|
||||
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -49,8 +46,7 @@ public abstract class AbstractClassLoaderTest<T> extends AbstractITest {
|
||||
|
||||
Field mongoSessionConverterField = ReflectionUtils.findField(this.sessionRepository.getClass(),
|
||||
"mongoSessionConverter");
|
||||
ReflectionUtils.makeAccessible(
|
||||
Assert.requireNonNull(mongoSessionConverterField, "mongoSessionConverter must not be null!"));
|
||||
ReflectionUtils.makeAccessible(mongoSessionConverterField);
|
||||
AbstractMongoSessionConverter sessionConverter = (AbstractMongoSessionConverter) ReflectionUtils
|
||||
.getField(mongoSessionConverterField, this.sessionRepository);
|
||||
|
||||
@@ -70,7 +66,7 @@ public abstract class AbstractClassLoaderTest<T> extends AbstractITest {
|
||||
private static Object extractField(Class<?> clazz, String fieldName, Object obj) {
|
||||
|
||||
Field field = ReflectionUtils.findField(clazz, fieldName);
|
||||
ReflectionUtils.makeAccessible(Assert.requireNonNull(field, fieldName + " must not be null!"));
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return ReflectionUtils.getField(field, obj);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -37,8 +37,6 @@ import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@@ -41,8 +41,6 @@ import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.config.annotation.web.reactive.EnableMongoWebSession;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -25,9 +25,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.geo.GeoModule;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo.integration;
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
@@ -23,9 +23,6 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,8 @@ import org.springframework.session.DelegatingIndexResolver;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.PrincipalNameIndexResolver;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for serializing and deserializing session objects. To create custom
|
||||
@@ -54,8 +56,7 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
private IndexResolver<MongoSession> indexResolver = new DelegatingIndexResolver<>(
|
||||
new PrincipalNameIndexResolver<>());
|
||||
private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
|
||||
|
||||
/**
|
||||
* Returns query to be executed to return sessions based on a particular index.
|
||||
@@ -122,8 +123,9 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter
|
||||
|
||||
protected abstract MongoSession convert(Document sessionWrapper);
|
||||
|
||||
public void setIndexResolver(IndexResolver<MongoSession> indexResolver) {
|
||||
this.indexResolver = Assert.requireNonNull(indexResolver, "indexResolver must not be null!");
|
||||
public void setIndexResolver(IndexResolver<Session> indexResolver) {
|
||||
Assert.notNull(indexResolver, "indexResolver must not be null");
|
||||
this.indexResolver = indexResolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Utility to verify non null fields.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public final class Assert {
|
||||
|
||||
private Assert() {
|
||||
}
|
||||
|
||||
public static <T> T requireNonNull(@Nullable T item, String message) {
|
||||
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bson.Document;
|
||||
@@ -34,9 +35,11 @@ import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Session repository implementation which stores sessions in Mongo. Uses
|
||||
@@ -46,6 +49,7 @@ import org.springframework.session.events.SessionExpiredEvent;
|
||||
*
|
||||
* @author Jakub Kubrynski
|
||||
* @author Greg Turnquist
|
||||
* @author Vedran Pavic
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class MongoIndexedSessionRepository
|
||||
@@ -53,8 +57,11 @@ public class MongoIndexedSessionRepository
|
||||
|
||||
/**
|
||||
* The default time period in seconds in which a session will expire.
|
||||
* @deprecated since 3.0.0 in favor of
|
||||
* {@link MapSession#DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS}
|
||||
*/
|
||||
public static final int DEFAULT_INACTIVE_INTERVAL = 1800;
|
||||
@Deprecated
|
||||
public static final int DEFAULT_INACTIVE_INTERVAL = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
|
||||
/**
|
||||
* the default collection name for storing session.
|
||||
@@ -65,12 +72,12 @@ public class MongoIndexedSessionRepository
|
||||
|
||||
private final MongoOperations mongoOperations;
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private String collectionName = DEFAULT_COLLECTION_NAME;
|
||||
|
||||
private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
|
||||
Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
|
||||
this.defaultMaxInactiveInterval);
|
||||
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@@ -83,9 +90,7 @@ public class MongoIndexedSessionRepository
|
||||
|
||||
MongoSession session = new MongoSession();
|
||||
|
||||
if (this.maxInactiveIntervalInSeconds != null) {
|
||||
session.setMaxInactiveInterval(Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
|
||||
}
|
||||
session.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
|
||||
publishEvent(new SessionCreatedEvent(this, session));
|
||||
|
||||
@@ -94,9 +99,9 @@ public class MongoIndexedSessionRepository
|
||||
|
||||
@Override
|
||||
public void save(MongoSession session) {
|
||||
this.mongoOperations
|
||||
.save(Assert.requireNonNull(MongoSessionUtils.convertToDBObject(this.mongoSessionConverter, session),
|
||||
"convertToDBObject must not null!"), this.collectionName);
|
||||
DBObject dbObject = MongoSessionUtils.convertToDBObject(this.mongoSessionConverter, session);
|
||||
Assert.notNull(dbObject, "dbObject must not be null");
|
||||
this.mongoOperations.save(dbObject, this.collectionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,8 +183,29 @@ public class MongoIndexedSessionRepository
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(final Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
org.springframework.util.Assert.notNull(defaultMaxInactiveInterval,
|
||||
"defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
|
||||
* @deprecated since 3.0.0, in favor of
|
||||
* {@link #setDefaultMaxInactiveInterval(Duration)}
|
||||
*/
|
||||
@Deprecated(since = "3.0.0")
|
||||
public void setMaxInactiveIntervalInSeconds(Integer defaultMaxInactiveInterval) {
|
||||
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
|
||||
}
|
||||
|
||||
public void setCollectionName(final String collectionName) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
|
||||
/**
|
||||
@@ -36,7 +37,7 @@ import org.springframework.session.Session;
|
||||
* @author Greg Turnquist
|
||||
* @since 1.2
|
||||
*/
|
||||
public class MongoSession implements Session {
|
||||
class MongoSession implements Session {
|
||||
|
||||
/**
|
||||
* Mongo doesn't support {@literal dot} in field names. We replace it with a unicode
|
||||
@@ -65,15 +66,15 @@ public class MongoSession implements Session {
|
||||
|
||||
private Map<String, Object> attrs = new HashMap<>();
|
||||
|
||||
public MongoSession() {
|
||||
this(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
MongoSession() {
|
||||
this(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
}
|
||||
|
||||
public MongoSession(long maxInactiveIntervalInSeconds) {
|
||||
MongoSession(long maxInactiveIntervalInSeconds) {
|
||||
this(UUID.randomUUID().toString(), maxInactiveIntervalInSeconds);
|
||||
}
|
||||
|
||||
public MongoSession(String id, long maxInactiveIntervalInSeconds) {
|
||||
MongoSession(String id, long maxInactiveIntervalInSeconds) {
|
||||
|
||||
this.id = id;
|
||||
this.originalSessionId = id;
|
||||
@@ -129,7 +130,7 @@ public class MongoSession implements Session {
|
||||
return Instant.ofEpochMilli(this.createdMillis);
|
||||
}
|
||||
|
||||
public void setCreationTime(long created) {
|
||||
void setCreationTime(long created) {
|
||||
this.createdMillis = created;
|
||||
}
|
||||
|
||||
@@ -183,11 +184,11 @@ public class MongoSession implements Session {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Date getExpireAt() {
|
||||
Date getExpireAt() {
|
||||
return this.expireAt;
|
||||
}
|
||||
|
||||
public void setExpireAt(final Date expireAt) {
|
||||
void setExpireAt(final Date expireAt) {
|
||||
this.expireAt = expireAt;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,7 +27,7 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public final class MongoSessionUtils {
|
||||
final class MongoSessionUtils {
|
||||
|
||||
private MongoSessionUtils() {
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,14 +32,17 @@ import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ReactiveSessionRepository} implementation that uses Spring Data MongoDB.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Vedran Pavic
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class ReactiveMongoSessionRepository
|
||||
@@ -47,8 +50,11 @@ public class ReactiveMongoSessionRepository
|
||||
|
||||
/**
|
||||
* The default time period in seconds in which a session will expire.
|
||||
* @deprecated since 3.0.0 in favor of
|
||||
* {@link MapSession#DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS}
|
||||
*/
|
||||
public static final int DEFAULT_INACTIVE_INTERVAL = 1800;
|
||||
@Deprecated
|
||||
public static final int DEFAULT_INACTIVE_INTERVAL = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
|
||||
/**
|
||||
* The default collection name for storing session.
|
||||
@@ -59,12 +65,12 @@ public class ReactiveMongoSessionRepository
|
||||
|
||||
private final ReactiveMongoOperations mongoOperations;
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private String collectionName = DEFAULT_COLLECTION_NAME;
|
||||
|
||||
private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
|
||||
Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
|
||||
this.defaultMaxInactiveInterval);
|
||||
|
||||
private MongoOperations blockingMongoOperations;
|
||||
|
||||
@@ -88,7 +94,7 @@ public class ReactiveMongoSessionRepository
|
||||
@Override
|
||||
public Mono<MongoSession> createSession() {
|
||||
|
||||
return Mono.justOrEmpty(this.maxInactiveIntervalInSeconds) //
|
||||
return Mono.justOrEmpty(this.defaultMaxInactiveInterval.toSeconds()) //
|
||||
.map(MongoSession::new) //
|
||||
.doOnNext((mongoSession) -> publishEvent(new SessionCreatedEvent(this, mongoSession))) //
|
||||
.switchIfEmpty(Mono.just(new MongoSession()));
|
||||
@@ -170,12 +176,28 @@ public class ReactiveMongoSessionRepository
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getMaxInactiveIntervalInSeconds() {
|
||||
return this.maxInactiveIntervalInSeconds;
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(final Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
|
||||
* @deprecated since 3.0.0, in favor of
|
||||
* {@link #setDefaultMaxInactiveInterval(Duration)}
|
||||
*/
|
||||
@Deprecated(since = "3.0.0")
|
||||
public void setMaxInactiveIntervalInSeconds(Integer defaultMaxInactiveInterval) {
|
||||
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
|
||||
}
|
||||
|
||||
public String getCollectionName() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,8 +22,8 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
|
||||
/**
|
||||
@@ -34,6 +34,7 @@ import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @Configuration(proxyBeanMethods = false)}
|
||||
* {@literal @EnableMongoHttpSession}
|
||||
* public class MongoHttpSessionConfig {
|
||||
*
|
||||
@@ -52,14 +53,13 @@ import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(MongoHttpSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableMongoHttpSession {
|
||||
|
||||
/**
|
||||
* The maximum time a session will be kept if it is inactive.
|
||||
* @return default max inactive interval in seconds
|
||||
*/
|
||||
int maxInactiveIntervalInSeconds() default MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL;
|
||||
int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
|
||||
/**
|
||||
* The collection name to use.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
@@ -33,12 +34,13 @@ import org.springframework.core.serializer.support.SerializingConverter;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
@@ -51,12 +53,12 @@ import org.springframework.util.StringValueResolver;
|
||||
* @since 1.2
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
@Import(SpringHttpSessionConfiguration.class)
|
||||
public class MongoHttpSessionConfiguration implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
|
||||
private AbstractMongoSessionConverter mongoSessionConverter;
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds;
|
||||
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private String collectionName;
|
||||
|
||||
@@ -66,13 +68,13 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private IndexResolver<MongoSession> indexResolver;
|
||||
private IndexResolver<Session> indexResolver;
|
||||
|
||||
@Bean
|
||||
public MongoIndexedSessionRepository mongoSessionRepository(MongoOperations mongoOperations) {
|
||||
|
||||
MongoIndexedSessionRepository repository = new MongoIndexedSessionRepository(mongoOperations);
|
||||
repository.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
|
||||
repository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
|
||||
|
||||
if (this.mongoSessionConverter != null) {
|
||||
repository.setMongoSessionConverter(this.mongoSessionConverter);
|
||||
@@ -84,7 +86,7 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
else {
|
||||
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(new SerializingConverter(),
|
||||
new DeserializingConverter(this.classLoader),
|
||||
Duration.ofSeconds(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL));
|
||||
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
|
||||
|
||||
if (this.indexResolver != null) {
|
||||
mongoSessionConverter.setIndexResolver(this.indexResolver);
|
||||
@@ -107,8 +109,13 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
this.collectionName = collectionName;
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
|
||||
}
|
||||
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
@@ -117,10 +124,8 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
.fromMap(importMetadata.getAnnotationAttributes(EnableMongoHttpSession.class.getName()));
|
||||
|
||||
if (attributes != null) {
|
||||
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
|
||||
}
|
||||
else {
|
||||
this.maxInactiveIntervalInSeconds = MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL;
|
||||
this.maxInactiveInterval = Duration
|
||||
.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
|
||||
}
|
||||
|
||||
String collectionNameValue = (attributes != null) ? attributes.getString("collectionName") : "";
|
||||
@@ -151,7 +156,7 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setIndexResolver(IndexResolver<MongoSession> indexResolver) {
|
||||
public void setIndexResolver(IndexResolver<Session> indexResolver) {
|
||||
this.indexResolver = indexResolver;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,8 +20,8 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @Configuration}
|
||||
* {@literal @Configuration(proxyBeanMethods = false)}
|
||||
* {@literal @EnableMongoWebSession}
|
||||
* public class SpringWebFluxConfig {
|
||||
*
|
||||
@@ -45,21 +45,20 @@ import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
* </code> </pre>
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Vedran Pavić
|
||||
* @author Vedran Pavic
|
||||
* @since 2.0
|
||||
*/
|
||||
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@Target({ java.lang.annotation.ElementType.TYPE })
|
||||
@Documented
|
||||
@Import(ReactiveMongoWebSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableMongoWebSession {
|
||||
|
||||
/**
|
||||
* The maximum time a session will be kept if it is inactive.
|
||||
* @return default max inactive interval in seconds
|
||||
*/
|
||||
int maxInactiveIntervalInSeconds() default ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL;
|
||||
int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
|
||||
/**
|
||||
* The collection name to use.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2016-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
@@ -34,11 +35,12 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
|
||||
import org.springframework.session.config.annotation.web.server.SpringWebSessionConfiguration;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
@@ -48,15 +50,16 @@ import org.springframework.util.StringValueResolver;
|
||||
* {@link ReactiveMongoOperations}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Vedran Pavić
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
@Import(SpringWebSessionConfiguration.class)
|
||||
public class ReactiveMongoWebSessionConfiguration
|
||||
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
|
||||
private AbstractMongoSessionConverter mongoSessionConverter;
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds;
|
||||
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private String collectionName;
|
||||
|
||||
@@ -69,7 +72,7 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private IndexResolver<MongoSession> indexResolver;
|
||||
private IndexResolver<Session> indexResolver;
|
||||
|
||||
@Bean
|
||||
public ReactiveMongoSessionRepository reactiveMongoSessionRepository(ReactiveMongoOperations operations) {
|
||||
@@ -87,7 +90,7 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
|
||||
else {
|
||||
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(new SerializingConverter(),
|
||||
new DeserializingConverter(this.classLoader),
|
||||
Duration.ofSeconds(ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL));
|
||||
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
|
||||
|
||||
if (this.indexResolver != null) {
|
||||
mongoSessionConverter.setIndexResolver(this.indexResolver);
|
||||
@@ -96,9 +99,7 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
|
||||
repository.setMongoSessionConverter(mongoSessionConverter);
|
||||
}
|
||||
|
||||
if (this.maxInactiveIntervalInSeconds != null) {
|
||||
repository.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
|
||||
}
|
||||
repository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
|
||||
|
||||
if (this.collectionName != null) {
|
||||
repository.setCollectionName(this.collectionName);
|
||||
@@ -126,10 +127,8 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
|
||||
.fromMap(importMetadata.getAnnotationAttributes(EnableMongoWebSession.class.getName()));
|
||||
|
||||
if (attributes != null) {
|
||||
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
|
||||
}
|
||||
else {
|
||||
this.maxInactiveIntervalInSeconds = ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL;
|
||||
this.maxInactiveInterval = Duration
|
||||
.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
|
||||
}
|
||||
|
||||
String collectionNameValue = (attributes != null) ? attributes.getString("collectionName") : "";
|
||||
@@ -149,12 +148,17 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
|
||||
this.embeddedValueResolver = embeddedValueResolver;
|
||||
}
|
||||
|
||||
public Integer getMaxInactiveIntervalInSeconds() {
|
||||
return this.maxInactiveIntervalInSeconds;
|
||||
public Duration getMaxInactiveInterval() {
|
||||
return this.maxInactiveInterval;
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
|
||||
}
|
||||
|
||||
public String getCollectionName() {
|
||||
@@ -172,7 +176,7 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setIndexResolver(IndexResolver<MongoSession> indexResolver) {
|
||||
public void setIndexResolver(IndexResolver<Session> indexResolver) {
|
||||
this.indexResolver = indexResolver;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -76,20 +77,7 @@ public class MongoIndexedSessionRepositoryTest {
|
||||
// then
|
||||
assertThat(session.getId()).isNotEmpty();
|
||||
assertThat(session.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateSessionWhenMaxInactiveIntervalNotDefined() {
|
||||
|
||||
// when
|
||||
this.repository.setMaxInactiveIntervalInSeconds(null);
|
||||
MongoSession session = this.repository.createSession();
|
||||
|
||||
// then
|
||||
assertThat(session.getId()).isNotEmpty();
|
||||
assertThat(session.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
.isEqualTo(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,8 +152,7 @@ public class MongoIndexedSessionRepositoryTest {
|
||||
Document sessionDocument = new Document();
|
||||
sessionDocument.put("id", sessionId);
|
||||
|
||||
MongoSession mongoSession = new MongoSession(sessionId,
|
||||
MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
MongoSession mongoSession = new MongoSession(sessionId, MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
given(this.converter.convert(sessionDocument, TypeDescriptor.valueOf(Document.class),
|
||||
TypeDescriptor.valueOf(MongoSession.class))).willReturn(mongoSession);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.data.mongo;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -35,6 +36,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -84,26 +86,8 @@ public class ReactiveMongoSessionRepositoryTest {
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextMatches((mongoSession) -> {
|
||||
assertThat(mongoSession.getId()).isNotEmpty();
|
||||
assertThat(mongoSession.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
return true;
|
||||
}) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateSessionWhenMaxInactiveIntervalNotDefined() {
|
||||
|
||||
// when
|
||||
this.repository.setMaxInactiveIntervalInSeconds(null);
|
||||
|
||||
// then
|
||||
this.repository.createSession() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextMatches((mongoSession) -> {
|
||||
assertThat(mongoSession.getId()).isNotEmpty();
|
||||
assertThat(mongoSession.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(ReactiveMongoSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
assertThat(mongoSession.getMaxInactiveInterval())
|
||||
.isEqualTo(Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
|
||||
return true;
|
||||
}) //
|
||||
.verifyComplete();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.session.data.mongo.config.annotation.web.http;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
@@ -32,11 +33,11 @@ import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -112,9 +113,8 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
MongoIndexedSessionRepository repository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,9 +124,8 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
MongoIndexedSessionRepository repository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -161,7 +160,7 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
MongoIndexedSessionRepository sessionRepository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
|
||||
assertThat(sessionRepository).hasFieldOrPropertyWithValue("maxInactiveIntervalInSeconds", 10000);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ofSeconds(10000));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -171,7 +170,7 @@ public class MongoHttpSessionConfigurationTest {
|
||||
CustomIndexResolverConfigurationWithDefaultMongoSessionConverter.class);
|
||||
|
||||
MongoIndexedSessionRepository repository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
IndexResolver<MongoSession> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
IndexResolver<Session> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(indexResolver).isNotNull();
|
||||
@@ -186,7 +185,7 @@ public class MongoHttpSessionConfigurationTest {
|
||||
CustomIndexResolverConfigurationWithProvidedMongoSessionConverter.class);
|
||||
|
||||
MongoIndexedSessionRepository repository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
IndexResolver<MongoSession> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
IndexResolver<Session> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(indexResolver).isNotNull();
|
||||
@@ -194,6 +193,13 @@ public class MongoHttpSessionConfigurationTest {
|
||||
indexResolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
registerAndRefresh(ImportConfigAndCustomizeConfiguration.class);
|
||||
MongoIndexedSessionRepository sessionRepository = this.context.getBean(MongoIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
|
||||
this.context.register(annotatedClasses);
|
||||
@@ -259,7 +265,7 @@ public class MongoHttpSessionConfigurationTest {
|
||||
static class CustomMaxInactiveIntervalInSecondsSetConfiguration extends MongoHttpSessionConfiguration {
|
||||
|
||||
CustomMaxInactiveIntervalInSecondsSetConfiguration() {
|
||||
setMaxInactiveIntervalInSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
setMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -286,19 +292,20 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoHttpSession
|
||||
static class SessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
SessionRepositoryCustomizer<MongoIndexedSessionRepository> sessionRepositoryCustomizerOne() {
|
||||
return (sessionRepository) -> sessionRepository.setMaxInactiveIntervalInSeconds(0);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
SessionRepositoryCustomizer<MongoIndexedSessionRepository> sessionRepositoryCustomizerTwo() {
|
||||
return (sessionRepository) -> sessionRepository.setMaxInactiveIntervalInSeconds(10000);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ofSeconds(10000));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -309,7 +316,7 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
IndexResolver<MongoSession> indexResolver() {
|
||||
IndexResolver<Session> indexResolver() {
|
||||
return mock(IndexResolver.class);
|
||||
}
|
||||
|
||||
@@ -326,10 +333,21 @@ public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
IndexResolver<MongoSession> indexResolver() {
|
||||
IndexResolver<Session> indexResolver() {
|
||||
return mock(IndexResolver.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(MongoHttpSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<MongoIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.session.data.mongo.config.annotation.web.reactive;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -26,17 +27,19 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperations;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
|
||||
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JacksonMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoSession;
|
||||
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
@@ -54,7 +57,7 @@ import static org.mockito.BDDMockito.verify;
|
||||
* Verify various configurations through {@link EnableSpringWebSession}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Vedran Pavić
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
@@ -126,7 +129,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void overridingIntervalAndCollectionNameThroughAnnotationShouldWork() throws IllegalAccessException {
|
||||
void overridingIntervalAndCollectionNameThroughAnnotationShouldWork() {
|
||||
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(OverrideMongoParametersConfig.class);
|
||||
@@ -134,17 +137,8 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
ReactiveMongoSessionRepository repository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
|
||||
Field inactiveField = ReflectionUtils.findField(ReactiveMongoSessionRepository.class,
|
||||
"maxInactiveIntervalInSeconds");
|
||||
ReflectionUtils.makeAccessible(inactiveField);
|
||||
Integer inactiveSeconds = (Integer) inactiveField.get(repository);
|
||||
|
||||
Field collectionNameField = ReflectionUtils.findField(ReactiveMongoSessionRepository.class, "collectionName");
|
||||
ReflectionUtils.makeAccessible(collectionNameField);
|
||||
String collectionName = (String) collectionNameField.get(repository);
|
||||
|
||||
assertThat(inactiveSeconds).isEqualTo(123);
|
||||
assertThat(collectionName).isEqualTo("test-case");
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ofSeconds(123));
|
||||
assertThat(repository).extracting("collectionName").isEqualTo("test-case");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -172,7 +166,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
ReactiveMongoSessionRepository repository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
|
||||
assertThat(repository.getCollectionName()).isEqualTo("custom-collection");
|
||||
assertThat(repository.getMaxInactiveIntervalInSeconds()).isEqualTo(123);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ofSeconds(123));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -184,7 +178,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
ReactiveMongoSessionRepository repository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("maxInactiveIntervalInSeconds", 10000);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ofSeconds(10000));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -195,7 +189,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
this.context.refresh();
|
||||
|
||||
ReactiveMongoSessionRepository repository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
IndexResolver<MongoSession> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
IndexResolver<Session> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(indexResolver).isNotNull();
|
||||
@@ -211,7 +205,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
this.context.refresh();
|
||||
|
||||
ReactiveMongoSessionRepository repository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
IndexResolver<MongoSession> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
IndexResolver<Session> indexResolver = this.context.getBean(IndexResolver.class);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(indexResolver).isNotNull();
|
||||
@@ -219,6 +213,15 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
indexResolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(ImportConfigAndCustomizeConfiguration.class);
|
||||
this.context.refresh();
|
||||
ReactiveMongoSessionRepository sessionRepository = this.context.getBean(ReactiveMongoSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflectively extract the {@link AbstractMongoSessionConverter} from the
|
||||
* {@link ReactiveMongoSessionRepository}. This is to avoid expanding the surface area
|
||||
@@ -239,6 +242,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
/**
|
||||
* A configuration with all the right parts.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class GoodConfig {
|
||||
|
||||
@@ -252,11 +256,13 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
/**
|
||||
* A configuration where no {@link ReactiveMongoOperations} is defined. It's BAD!
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class BadConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class OverrideSessionConverterConfig {
|
||||
|
||||
@@ -272,6 +278,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession(maxInactiveIntervalInSeconds = 123, collectionName = "test-case")
|
||||
static class OverrideMongoParametersConfig {
|
||||
|
||||
@@ -282,6 +289,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class ConfigWithReactiveAndImperativeMongoOperations {
|
||||
|
||||
@@ -308,13 +316,14 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableSpringWebSession
|
||||
static class CustomizedReactiveConfiguration extends ReactiveMongoWebSessionConfiguration {
|
||||
|
||||
CustomizedReactiveConfiguration() {
|
||||
|
||||
this.setCollectionName("custom-collection");
|
||||
this.setMaxInactiveIntervalInSeconds(123);
|
||||
this.setMaxInactiveInterval(Duration.ofSeconds(123));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -324,6 +333,7 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class SessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@@ -335,17 +345,18 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
@Bean
|
||||
@Order(0)
|
||||
ReactiveSessionRepositoryCustomizer<ReactiveMongoSessionRepository> sessionRepositoryCustomizerOne() {
|
||||
return (sessionRepository) -> sessionRepository.setMaxInactiveIntervalInSeconds(0);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
ReactiveSessionRepositoryCustomizer<ReactiveMongoSessionRepository> sessionRepositoryCustomizerTwo() {
|
||||
return (sessionRepository) -> sessionRepository.setMaxInactiveIntervalInSeconds(10000);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ofSeconds(10000));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class CustomIndexResolverConfigurationWithDefaultMongoSessionConverter {
|
||||
|
||||
@@ -356,12 +367,13 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
IndexResolver<MongoSession> indexResolver() {
|
||||
IndexResolver<Session> indexResolver() {
|
||||
return mock(IndexResolver.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoWebSession
|
||||
static class CustomIndexResolverConfigurationWithProvidedtMongoSessionConverter {
|
||||
|
||||
@@ -377,10 +389,26 @@ public class ReactiveMongoWebSessionConfigurationTest {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
IndexResolver<MongoSession> indexResolver() {
|
||||
IndexResolver<Session> indexResolver() {
|
||||
return mock(IndexResolver.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ReactiveMongoWebSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration {
|
||||
|
||||
@Bean
|
||||
ReactiveMongoOperations operations() {
|
||||
return mock(ReactiveMongoOperations.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactiveSessionRepositoryCustomizer<ReactiveMongoSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -111,10 +111,10 @@ class RedisIndexedSessionRepositoryITests extends AbstractRedisITests {
|
||||
this.repository.save(toSave);
|
||||
|
||||
assertThat(this.registry.receivedEvent(toSave.getId())).isTrue();
|
||||
assertThat(this.registry.<SessionCreatedEvent>getEvent(toSave.getId())).isInstanceOf(SessionCreatedEvent.class);
|
||||
assertThat(this.redis.boundSetOps(usernameSessionKey).members()).contains(toSave.getId());
|
||||
|
||||
Session session = this.repository.findById(toSave.getId());
|
||||
SessionCreatedEvent createdEvent = this.registry.getEvent(toSave.getId());
|
||||
Session session = createdEvent.getSession();
|
||||
|
||||
assertThat(session.getId()).isEqualTo(toSave.getId());
|
||||
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,11 +55,7 @@ public class ReactiveRedisSessionRepository
|
||||
*/
|
||||
private String namespace = DEFAULT_NAMESPACE + ":";
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override the default value for
|
||||
* {@link RedisSession#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
|
||||
|
||||
@@ -79,16 +75,29 @@ public class ReactiveRedisSessionRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum inactive interval in seconds between requests before newly created
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* timeout. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
|
||||
* should be kept alive between client requests.
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
|
||||
* @deprecated since 3.0.0, in favor of
|
||||
* {@link #setDefaultMaxInactiveInterval(Duration)}
|
||||
*/
|
||||
@Deprecated(since = "3.0.0")
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the save mode.
|
||||
* @param saveMode the save mode
|
||||
@@ -110,9 +119,7 @@ public class ReactiveRedisSessionRepository
|
||||
public Mono<RedisSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
MapSession cached = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
RedisSession session = new RedisSession(cached, true);
|
||||
return Mono.just(session);
|
||||
});
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.util.Set;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.core.NestedExceptionUtils;
|
||||
@@ -38,6 +40,10 @@ import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.util.ByteUtils;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.scheduling.support.CronExpression;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import org.springframework.session.DelegatingIndexResolver;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.FlushMode;
|
||||
@@ -249,12 +255,18 @@ import org.springframework.util.Assert;
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class RedisIndexedSessionRepository
|
||||
implements FindByIndexNameSessionRepository<RedisIndexedSessionRepository.RedisSession>, MessageListener {
|
||||
implements FindByIndexNameSessionRepository<RedisIndexedSessionRepository.RedisSession>, MessageListener,
|
||||
InitializingBean, DisposableBean {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RedisIndexedSessionRepository.class);
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
/**
|
||||
* The default cron expression used for expired session cleanup job.
|
||||
*/
|
||||
public static final String DEFAULT_CLEANUP_CRON = "0 * * * * *";
|
||||
|
||||
/**
|
||||
* The default Redis database used by Spring Session.
|
||||
*/
|
||||
@@ -295,11 +307,7 @@ public class RedisIndexedSessionRepository
|
||||
private ApplicationEventPublisher eventPublisher = (event) -> {
|
||||
};
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override the default value for
|
||||
* {@link RedisSession#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
|
||||
|
||||
@@ -309,6 +317,10 @@ public class RedisIndexedSessionRepository
|
||||
|
||||
private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
|
||||
|
||||
private String cleanupCron = DEFAULT_CLEANUP_CRON;
|
||||
|
||||
private ThreadPoolTaskScheduler taskScheduler;
|
||||
|
||||
/**
|
||||
* Creates a new instance. For an example, refer to the class level javadoc.
|
||||
* @param sessionRedisOperations the {@link RedisOperations} to use for managing the
|
||||
@@ -322,6 +334,28 @@ public class RedisIndexedSessionRepository
|
||||
configureSessionChannels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (!Scheduled.CRON_DISABLED.equals(this.cleanupCron)) {
|
||||
this.taskScheduler = createTaskScheduler();
|
||||
this.taskScheduler.initialize();
|
||||
this.taskScheduler.schedule(this::cleanUpExpiredSessions, new CronTrigger(this.cleanupCron));
|
||||
}
|
||||
}
|
||||
|
||||
private static ThreadPoolTaskScheduler createTaskScheduler() {
|
||||
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||
taskScheduler.setThreadNamePrefix("spring-session-");
|
||||
return taskScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.taskScheduler != null) {
|
||||
this.taskScheduler.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ApplicationEventPublisher} that is used to publish
|
||||
* {@link SessionDestroyedEvent}. The default is to not publish a
|
||||
@@ -335,16 +369,29 @@ public class RedisIndexedSessionRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum inactive interval in seconds between requests before newly created
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* timeout. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
|
||||
* should be kept alive between client requests.
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
|
||||
* @deprecated since 3.0.0, in favor of
|
||||
* {@link #setDefaultMaxInactiveInterval(Duration)}
|
||||
*/
|
||||
@Deprecated(since = "3.0.0")
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link IndexResolver} to use.
|
||||
* @param indexResolver the index resolver
|
||||
@@ -382,6 +429,21 @@ public class RedisIndexedSessionRepository
|
||||
this.saveMode = saveMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cleanup cron expression.
|
||||
* @param cleanupCron the cleanup cron expression
|
||||
* @since 3.0.0
|
||||
* @see CronExpression
|
||||
* @see Scheduled#CRON_DISABLED
|
||||
*/
|
||||
public void setCleanupCron(String cleanupCron) {
|
||||
Assert.notNull(cleanupCron, "cleanupCron must not be null");
|
||||
if (!Scheduled.CRON_DISABLED.equals(cleanupCron)) {
|
||||
Assert.isTrue(CronExpression.isValidExpression(cleanupCron), "cleanupCron must be valid");
|
||||
}
|
||||
this.cleanupCron = cleanupCron;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database index to use. Defaults to {@link #DEFAULT_DATABASE}.
|
||||
* @param database the database index to use
|
||||
@@ -413,14 +475,9 @@ public class RedisIndexedSessionRepository
|
||||
@Override
|
||||
public void save(RedisSession session) {
|
||||
session.save();
|
||||
if (session.isNew) {
|
||||
String sessionCreatedKey = getSessionCreatedChannel(session.getId());
|
||||
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
|
||||
session.isNew = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupExpiredSessions() {
|
||||
public void cleanUpExpiredSessions() {
|
||||
this.expirationPolicy.cleanExpiredSessions();
|
||||
}
|
||||
|
||||
@@ -436,6 +493,9 @@ public class RedisIndexedSessionRepository
|
||||
}
|
||||
String principalKey = getPrincipalKey(indexValue);
|
||||
Set<Object> sessionIds = this.sessionRedisOperations.boundSetOps(principalKey).members();
|
||||
if (sessionIds == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, RedisSession> sessions = new HashMap<>(sessionIds.size());
|
||||
for (Object id : sessionIds) {
|
||||
RedisSession session = findById((String) id);
|
||||
@@ -455,10 +515,10 @@ public class RedisIndexedSessionRepository
|
||||
*/
|
||||
private RedisSession getSession(String id, boolean allowExpired) {
|
||||
Map<String, Object> entries = getSessionBoundHashOperations(id).entries();
|
||||
if (entries.isEmpty()) {
|
||||
if ((entries == null) || entries.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
MapSession loaded = loadSession(id, entries);
|
||||
MapSession loaded = new RedisSessionMapper(id).apply(entries);
|
||||
if (!allowExpired && loaded.isExpired()) {
|
||||
return null;
|
||||
}
|
||||
@@ -467,26 +527,6 @@ public class RedisIndexedSessionRepository
|
||||
return result;
|
||||
}
|
||||
|
||||
private MapSession loadSession(String id, Map<String, Object> entries) {
|
||||
MapSession loaded = new MapSession(id);
|
||||
for (Map.Entry<String, Object> entry : entries.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (RedisSessionMapper.CREATION_TIME_KEY.equals(key)) {
|
||||
loaded.setCreationTime(Instant.ofEpochMilli((long) entry.getValue()));
|
||||
}
|
||||
else if (RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY.equals(key)) {
|
||||
loaded.setMaxInactiveInterval(Duration.ofSeconds((int) entry.getValue()));
|
||||
}
|
||||
else if (RedisSessionMapper.LAST_ACCESSED_TIME_KEY.equals(key)) {
|
||||
loaded.setLastAccessedTime(Instant.ofEpochMilli((long) entry.getValue()));
|
||||
}
|
||||
else if (key.startsWith(RedisSessionMapper.ATTRIBUTE_PREFIX)) {
|
||||
loaded.setAttribute(key.substring(RedisSessionMapper.ATTRIBUTE_PREFIX.length()), entry.getValue());
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(String sessionId) {
|
||||
RedisSession session = getSession(sessionId, true);
|
||||
@@ -507,9 +547,7 @@ public class RedisIndexedSessionRepository
|
||||
@Override
|
||||
public RedisSession createSession() {
|
||||
MapSession cached = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
RedisSession session = new RedisSession(cached, true);
|
||||
session.flushImmediateIfNecessary();
|
||||
return session;
|
||||
@@ -521,9 +559,13 @@ public class RedisIndexedSessionRepository
|
||||
|
||||
if (ByteUtils.startsWith(messageChannel, this.sessionCreatedChannelPrefixBytes)) {
|
||||
// TODO: is this thread safe?
|
||||
String channel = new String(messageChannel);
|
||||
String sessionId = channel.substring(channel.lastIndexOf(":") + 1);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> loaded = (Map<String, Object>) this.defaultSerializer.deserialize(message.getBody());
|
||||
handleCreated(loaded, new String(messageChannel));
|
||||
Map<String, Object> entries = (Map<String, Object>) this.defaultSerializer.deserialize(message.getBody());
|
||||
MapSession loaded = new RedisSessionMapper(sessionId).apply(entries);
|
||||
RedisSession session = new RedisSession(loaded, false);
|
||||
handleCreated(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -571,9 +613,7 @@ public class RedisIndexedSessionRepository
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCreated(Map<String, Object> loaded, String channel) {
|
||||
String id = channel.substring(channel.lastIndexOf(":") + 1);
|
||||
Session session = loadSession(id, loaded);
|
||||
private void handleCreated(RedisSession session) {
|
||||
publishEvent(new SessionCreatedEvent(this, session));
|
||||
}
|
||||
|
||||
@@ -827,9 +867,12 @@ public class RedisIndexedSessionRepository
|
||||
.add(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isNew) {
|
||||
String sessionCreatedKey = getSessionCreatedChannel(getId());
|
||||
RedisIndexedSessionRepository.this.sessionRedisOperations.convertAndSend(sessionCreatedKey, this.delta);
|
||||
this.isNew = false;
|
||||
}
|
||||
this.delta = new HashMap<>(this.delta.size());
|
||||
|
||||
Long originalExpiration = (this.originalLastAccessTime != null)
|
||||
? this.originalLastAccessTime.plus(getMaxInactiveInterval()).toEpochMilli() : null;
|
||||
RedisIndexedSessionRepository.this.expirationPolicy.onExpirationUpdated(originalExpiration, this);
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.session.data.redis;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -68,7 +67,9 @@ public class RedisSessionRepository implements SessionRepository<RedisSessionRep
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default maxInactiveInterval.
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
@@ -296,8 +297,8 @@ public class RedisSessionRepository implements SessionRepository<RedisSessionRep
|
||||
String key = getSessionKey(getId());
|
||||
RedisSessionRepository.this.sessionRedisOperations.opsForHash().putAll(key, new HashMap<>(this.delta));
|
||||
RedisSessionRepository.this.sessionRedisOperations.expireAt(key,
|
||||
Date.from(Instant.ofEpochMilli(getLastAccessedTime().toEpochMilli())
|
||||
.plusSeconds(getMaxInactiveInterval().getSeconds())));
|
||||
Instant.ofEpochMilli(getLastAccessedTime().toEpochMilli())
|
||||
.plusSeconds(getMaxInactiveInterval().getSeconds()));
|
||||
this.delta.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -24,6 +25,7 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
@@ -50,10 +52,11 @@ import org.springframework.util.Assert;
|
||||
* @see SpringSessionRedisConnectionFactory
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(SpringHttpSessionConfiguration.class)
|
||||
public abstract class AbstractRedisHttpSessionConfiguration<T extends SessionRepository<? extends Session>>
|
||||
extends SpringHttpSessionConfiguration implements BeanClassLoaderAware {
|
||||
implements BeanClassLoaderAware {
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private String redisNamespace = RedisSessionRepository.DEFAULT_KEY_NAMESPACE;
|
||||
|
||||
@@ -71,12 +74,17 @@ public abstract class AbstractRedisHttpSessionConfiguration<T extends SessionRep
|
||||
|
||||
public abstract T sessionRepository();
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
}
|
||||
|
||||
protected Integer getMaxInactiveIntervalInSeconds() {
|
||||
return this.maxInactiveIntervalInSeconds;
|
||||
@Deprecated
|
||||
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
|
||||
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
|
||||
}
|
||||
|
||||
protected Duration getMaxInactiveInterval() {
|
||||
return this.maxInactiveInterval;
|
||||
}
|
||||
|
||||
public void setRedisNamespace(String namespace) {
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.session.FlushMode;
|
||||
@@ -41,7 +40,7 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
* single {@link RedisConnectionFactory} must be provided. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @Configuration(proxyBeanMethods = false)
|
||||
* @EnableRedisHttpSession
|
||||
* public class RedisHttpSessionConfig {
|
||||
*
|
||||
@@ -64,7 +63,6 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(RedisHttpSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableRedisHttpSession {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.session.FlushMode;
|
||||
@@ -41,7 +40,7 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
* annotation, a single {@link RedisConnectionFactory} must be provided. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @Configuration(proxyBeanMethods = false)
|
||||
* @EnableRedisIndexedHttpSession
|
||||
* public class RedisHttpSessionConfig {
|
||||
*
|
||||
@@ -64,7 +63,6 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(RedisIndexedHttpSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableRedisIndexedHttpSession {
|
||||
|
||||
/**
|
||||
@@ -108,6 +106,6 @@ public @interface EnableRedisIndexedHttpSession {
|
||||
* The cron expression for expired session cleanup job. By default runs every minute.
|
||||
* @return the session cleanup cron expression
|
||||
*/
|
||||
String cleanupCron() default RedisIndexedHttpSessionConfiguration.DEFAULT_CLEANUP_CRON;
|
||||
String cleanupCron() default RedisIndexedSessionRepository.DEFAULT_CLEANUP_CRON;
|
||||
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class RedisHttpSessionConfiguration extends AbstractRedisHttpSessionConfi
|
||||
public RedisSessionRepository sessionRepository() {
|
||||
RedisTemplate<String, Object> redisTemplate = createRedisTemplate();
|
||||
RedisSessionRepository sessionRepository = new RedisSessionRepository(redisTemplate);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(Duration.ofSeconds(getMaxInactiveIntervalInSeconds()));
|
||||
sessionRepository.setDefaultMaxInactiveInterval(getMaxInactiveInterval());
|
||||
if (StringUtils.hasText(getRedisNamespace())) {
|
||||
sessionRepository.setRedisKeyNamespace(getRedisNamespace());
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public class RedisHttpSessionConfiguration extends AbstractRedisHttpSessionConfi
|
||||
if (attributes == null) {
|
||||
return;
|
||||
}
|
||||
setMaxInactiveIntervalInSeconds(attributes.getNumber("maxInactiveIntervalInSeconds"));
|
||||
setMaxInactiveInterval(Duration.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds")));
|
||||
String redisNamespaceValue = attributes.getString("redisNamespace");
|
||||
if (StringUtils.hasText(redisNamespaceValue)) {
|
||||
setRedisNamespace(this.embeddedValueResolver.resolveStringValue(redisNamespaceValue));
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -41,9 +42,6 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.PatternTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.redis.RedisIndexedSessionRepository;
|
||||
@@ -68,9 +66,7 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
extends AbstractRedisHttpSessionConfiguration<RedisIndexedSessionRepository>
|
||||
implements EmbeddedValueResolverAware, ImportAware {
|
||||
|
||||
static final String DEFAULT_CLEANUP_CRON = "0 * * * * *";
|
||||
|
||||
private String cleanupCron = DEFAULT_CLEANUP_CRON;
|
||||
private String cleanupCron = RedisIndexedSessionRepository.DEFAULT_CLEANUP_CRON;
|
||||
|
||||
private ConfigureRedisAction configureRedisAction = new ConfigureNotifyKeyspaceEventsAction();
|
||||
|
||||
@@ -96,12 +92,13 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
if (getDefaultRedisSerializer() != null) {
|
||||
sessionRepository.setDefaultSerializer(getDefaultRedisSerializer());
|
||||
}
|
||||
sessionRepository.setDefaultMaxInactiveInterval(getMaxInactiveIntervalInSeconds());
|
||||
sessionRepository.setDefaultMaxInactiveInterval(getMaxInactiveInterval());
|
||||
if (StringUtils.hasText(getRedisNamespace())) {
|
||||
sessionRepository.setRedisKeyNamespace(getRedisNamespace());
|
||||
}
|
||||
sessionRepository.setFlushMode(getFlushMode());
|
||||
sessionRepository.setSaveMode(getSaveMode());
|
||||
sessionRepository.setCleanupCron(this.cleanupCron);
|
||||
int database = resolveDatabase();
|
||||
sessionRepository.setDatabase(database);
|
||||
getSessionRepositoryCustomizers()
|
||||
@@ -182,7 +179,7 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
if (attributes == null) {
|
||||
return;
|
||||
}
|
||||
setMaxInactiveIntervalInSeconds(attributes.getNumber("maxInactiveIntervalInSeconds"));
|
||||
setMaxInactiveInterval(Duration.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds")));
|
||||
String redisNamespaceValue = attributes.getString("redisNamespace");
|
||||
if (StringUtils.hasText(redisNamespaceValue)) {
|
||||
setRedisNamespace(this.embeddedValueResolver.resolveStringValue(redisNamespaceValue));
|
||||
@@ -247,25 +244,4 @@ public class RedisIndexedHttpSessionConfiguration
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of scheduled job for cleaning up expired sessions.
|
||||
*/
|
||||
@EnableScheduling
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class SessionCleanupConfiguration implements SchedulingConfigurer {
|
||||
|
||||
private final RedisIndexedSessionRepository sessionRepository;
|
||||
|
||||
SessionCleanupConfiguration(RedisIndexedSessionRepository sessionRepository) {
|
||||
this.sessionRepository = sessionRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||
taskRegistrar.addCronTask(this.sessionRepository::cleanupExpiredSessions,
|
||||
RedisIndexedHttpSessionConfiguration.this.cleanupCron);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
import org.springframework.session.MapSession;
|
||||
@@ -38,7 +37,7 @@ import org.springframework.web.server.session.WebSessionManager;
|
||||
* {@link ReactiveRedisConnectionFactory} must be provided. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @Configuration(proxyBeanMethods = false)
|
||||
* @EnableRedisWebSession
|
||||
* public class RedisWebSessionConfig {
|
||||
*
|
||||
@@ -61,7 +60,6 @@ import org.springframework.web.server.session.WebSessionManager;
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(RedisWebSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableRedisWebSession {
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.server;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -56,10 +58,10 @@ import org.springframework.web.server.session.WebSessionManager;
|
||||
* @see EnableRedisWebSession
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
@Import(SpringWebSessionConfiguration.class)
|
||||
public class RedisWebSessionConfiguration implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private String redisNamespace = ReactiveRedisSessionRepository.DEFAULT_NAMESPACE;
|
||||
|
||||
@@ -79,7 +81,7 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
public ReactiveRedisSessionRepository sessionRepository() {
|
||||
ReactiveRedisTemplate<String, Object> reactiveRedisTemplate = createReactiveRedisTemplate();
|
||||
ReactiveRedisSessionRepository sessionRepository = new ReactiveRedisSessionRepository(reactiveRedisTemplate);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
|
||||
if (StringUtils.hasText(this.redisNamespace)) {
|
||||
sessionRepository.setRedisKeyNamespace(this.redisNamespace);
|
||||
}
|
||||
@@ -89,8 +91,13 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
|
||||
}
|
||||
|
||||
public void setRedisNamespace(String namespace) {
|
||||
@@ -140,7 +147,10 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
|
||||
Map<String, Object> attributeMap = importMetadata
|
||||
.getAnnotationAttributes(EnableRedisWebSession.class.getName());
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributeMap);
|
||||
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
|
||||
if (attributes == null) {
|
||||
return;
|
||||
}
|
||||
this.maxInactiveInterval = Duration.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
|
||||
String redisNamespaceValue = attributes.getString("redisNamespace");
|
||||
if (StringUtils.hasText(redisNamespaceValue)) {
|
||||
this.redisNamespace = this.embeddedValueResolver.resolveStringValue(redisNamespaceValue);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -103,9 +103,10 @@ class ReactiveRedisSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
void customMaxInactiveInterval() {
|
||||
this.repository.setDefaultMaxInactiveInterval(600);
|
||||
Duration interval = Duration.ofMinutes(10);
|
||||
this.repository.setDefaultMaxInactiveInterval(interval);
|
||||
|
||||
assertThat(ReflectionTestUtils.getField(this.repository, "defaultMaxInactiveInterval")).isEqualTo(600);
|
||||
assertThat(this.repository).extracting("defaultMaxInactiveInterval").isEqualTo(interval);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,11 +119,11 @@ class ReactiveRedisSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
void createSessionCustomMaxInactiveInterval() {
|
||||
this.repository.setDefaultMaxInactiveInterval(600);
|
||||
Duration interval = Duration.ofMinutes(10);
|
||||
this.repository.setDefaultMaxInactiveInterval(interval);
|
||||
|
||||
StepVerifier.create(this.repository.createSession())
|
||||
.consumeNextWith(
|
||||
(session) -> assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(600)))
|
||||
.consumeNextWith((session) -> assertThat(session.getMaxInactiveInterval()).isEqualTo(interval))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.springframework.data.redis.core.BoundValueOperations;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.MapSession;
|
||||
@@ -157,10 +158,10 @@ class RedisIndexedSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
void createSessionCustomMaxInactiveInterval() {
|
||||
int interval = 1;
|
||||
Duration interval = Duration.ofSeconds(1);
|
||||
this.redisRepository.setDefaultMaxInactiveInterval(interval);
|
||||
Session session = this.redisRepository.createSession();
|
||||
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(interval));
|
||||
assertThat(session.getMaxInactiveInterval()).isEqualTo(interval);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -310,7 +311,6 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void delete() {
|
||||
String attrName = "attrName";
|
||||
MapSession expected = new MapSession();
|
||||
@@ -318,10 +318,11 @@ class RedisIndexedSessionRepositoryTests {
|
||||
expected.setAttribute(attrName, "attrValue");
|
||||
given(this.redisOperations.<String, Object>boundHashOps(anyString())).willReturn(this.boundHashOperations);
|
||||
given(this.redisOperations.boundSetOps(anyString())).willReturn(this.boundSetOperations);
|
||||
Map map = map(RedisIndexedSessionRepository.getSessionAttrNameKey(attrName), expected.getAttribute(attrName),
|
||||
RedisSessionMapper.CREATION_TIME_KEY, expected.getCreationTime().toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, (int) expected.getMaxInactiveInterval().getSeconds(),
|
||||
RedisSessionMapper.LAST_ACCESSED_TIME_KEY, expected.getLastAccessedTime().toEpochMilli());
|
||||
Map<String, Object> map = map(RedisIndexedSessionRepository.getSessionAttrNameKey(attrName),
|
||||
expected.getAttribute(attrName), RedisSessionMapper.CREATION_TIME_KEY,
|
||||
expected.getCreationTime().toEpochMilli(), RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY,
|
||||
(int) expected.getMaxInactiveInterval().getSeconds(), RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
expected.getLastAccessedTime().toEpochMilli());
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
given(this.redisOperations.boundSetOps(anyString())).willReturn(this.boundSetOperations);
|
||||
|
||||
@@ -344,7 +345,6 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void getSessionNotFound() {
|
||||
String id = "abc";
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(id))).willReturn(this.boundHashOperations);
|
||||
@@ -354,7 +354,6 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void getSessionFound() {
|
||||
String attribute1 = "attribute1";
|
||||
String attribute2 = "attribute2";
|
||||
@@ -364,7 +363,7 @@ class RedisIndexedSessionRepositoryTests {
|
||||
expected.setAttribute(attribute2, null);
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(expected.getId())))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisIndexedSessionRepository.getSessionAttrNameKey(attribute1),
|
||||
Map<String, Object> map = map(RedisIndexedSessionRepository.getSessionAttrNameKey(attribute1),
|
||||
expected.getAttribute(attribute1), RedisIndexedSessionRepository.getSessionAttrNameKey(attribute2),
|
||||
expected.getAttribute(attribute2), RedisSessionMapper.CREATION_TIME_KEY,
|
||||
expected.getCreationTime().toEpochMilli(), RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY,
|
||||
@@ -385,12 +384,12 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void getSessionExpired() {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 1, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 1, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
Instant.now().minus(5, ChronoUnit.MINUTES).toEpochMilli());
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
@@ -398,14 +397,14 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void findByPrincipalNameExpired() {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.boundSetOps(anyString())).willReturn(this.boundSetOperations);
|
||||
given(this.boundSetOperations.members()).willReturn(Collections.singleton(expiredId));
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 1, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 1, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
Instant.now().minus(5, ChronoUnit.MINUTES).toEpochMilli());
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
@@ -415,7 +414,6 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void findByPrincipalName() {
|
||||
Instant lastAccessed = Instant.now().minusMillis(10);
|
||||
Instant createdTime = lastAccessed.minusMillis(10);
|
||||
@@ -425,7 +423,7 @@ class RedisIndexedSessionRepositoryTests {
|
||||
given(this.boundSetOperations.members()).willReturn(Collections.singleton(sessionId));
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(sessionId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisSessionMapper.CREATION_TIME_KEY, createdTime.toEpochMilli(),
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, createdTime.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, (int) maxInactive.getSeconds(),
|
||||
RedisSessionMapper.LAST_ACCESSED_TIME_KEY, lastAccessed.toEpochMilli());
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
@@ -451,7 +449,7 @@ class RedisIndexedSessionRepositoryTests {
|
||||
Set<Object> expiredIds = new HashSet<>(Arrays.asList("expired-key1", "expired-key2"));
|
||||
given(this.boundSetOperations.members()).willReturn(expiredIds);
|
||||
|
||||
this.redisRepository.cleanupExpiredSessions();
|
||||
this.redisRepository.cleanUpExpiredSessions();
|
||||
|
||||
for (Object id : expiredIds) {
|
||||
String expiredKey = "spring:session:sessions:" + id;
|
||||
@@ -467,7 +465,10 @@ class RedisIndexedSessionRepositoryTests {
|
||||
String channel = "spring:session:event:0:created:" + session.getId();
|
||||
JdkSerializationRedisSerializer defaultSerailizer = new JdkSerializationRedisSerializer();
|
||||
this.redisRepository.setDefaultSerializer(defaultSerailizer);
|
||||
byte[] body = defaultSerailizer.serialize(new HashMap());
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 0, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
byte[] body = defaultSerailizer.serialize(map);
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes(StandardCharsets.UTF_8), body);
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
@@ -484,7 +485,10 @@ class RedisIndexedSessionRepositoryTests {
|
||||
byte[] pattern = "".getBytes(StandardCharsets.UTF_8);
|
||||
byte[] body = new byte[0];
|
||||
String channel = "spring:session:event:0:created:" + session.getId();
|
||||
given(this.defaultSerializer.deserialize(body)).willReturn(new HashMap<String, Object>());
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 0, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.defaultSerializer.deserialize(body)).willReturn(map);
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes(StandardCharsets.UTF_8), body);
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
|
||||
@@ -496,12 +500,12 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void onMessageDeletedSessionFound() {
|
||||
String deletedId = "deleted-id";
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(deletedId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 0, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 0, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
@@ -524,7 +528,6 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void onMessageDeletedSessionNotFound() {
|
||||
String deletedId = "deleted-id";
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(deletedId)))
|
||||
@@ -548,12 +551,12 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void onMessageExpiredSessionFound() {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 1, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
Map<String, Object> map = map(RedisSessionMapper.CREATION_TIME_KEY, Instant.EPOCH.toEpochMilli(),
|
||||
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, 1, RedisSessionMapper.LAST_ACCESSED_TIME_KEY,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
@@ -576,7 +579,6 @@ class RedisIndexedSessionRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void onMessageExpiredSessionNotFound() {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.<String, Object>boundHashOps(getKey(expiredId)))
|
||||
@@ -662,7 +664,7 @@ class RedisIndexedSessionRepositoryTests {
|
||||
given(this.redisOperations.<String, Object>boundHashOps(anyString())).willReturn(this.boundHashOperations);
|
||||
given(this.redisOperations.boundSetOps(anyString())).willReturn(this.boundSetOperations);
|
||||
given(this.redisOperations.boundValueOps(anyString())).willReturn(this.boundValueOperations);
|
||||
this.redisRepository.setDefaultMaxInactiveInterval(60);
|
||||
this.redisRepository.setDefaultMaxInactiveInterval(Duration.ofSeconds(60));
|
||||
this.redisRepository.setFlushMode(FlushMode.IMMEDIATE);
|
||||
this.redisRepository.createSession();
|
||||
Map<String, Object> delta = getDelta();
|
||||
@@ -744,6 +746,25 @@ class RedisIndexedSessionRepositoryTests {
|
||||
.withMessage("flushMode cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCleanupCronNull() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.redisRepository.setCleanupCron(null))
|
||||
.withMessage("cleanupCron must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCleanupCronInvalid() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.redisRepository.setCleanupCron("test"))
|
||||
.withMessage("cleanupCron must be valid");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCleanupCronDisabled() {
|
||||
this.redisRepository.setCleanupCron(Scheduled.CRON_DISABLED);
|
||||
this.redisRepository.afterPropertiesSet();
|
||||
assertThat(this.redisRepository).extracting("taskScheduler").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void changeRedisNamespace() {
|
||||
String namespace = "foo:bar";
|
||||
@@ -793,7 +814,7 @@ class RedisIndexedSessionRepositoryTests {
|
||||
|
||||
MapSession session = this.cached;
|
||||
String channel = "spring:session:event:created:1:" + session.getId();
|
||||
byte[] body = serializer.serialize(new HashMap());
|
||||
byte[] body = serializer.serialize(new HashMap<>());
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes(StandardCharsets.UTF_8), body);
|
||||
|
||||
this.redisRepository.onMessage(message, "".getBytes(StandardCharsets.UTF_8));
|
||||
@@ -893,7 +914,7 @@ class RedisIndexedSessionRepositoryTests {
|
||||
return "spring:session:sessions:" + id;
|
||||
}
|
||||
|
||||
private Map map(Object... objects) {
|
||||
private Map<String, Object> map(Object... objects) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (objects == null) {
|
||||
return result;
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -378,9 +377,9 @@ class RedisSessionRepositoryTests {
|
||||
return "spring:session:sessions:" + sessionId;
|
||||
}
|
||||
|
||||
private static Date getExpiry(RedisSession session) {
|
||||
return Date.from(Instant.ofEpochMilli(session.getLastAccessedTime().toEpochMilli())
|
||||
.plusSeconds(session.getMaxInactiveInterval().getSeconds()));
|
||||
private static Instant getExpiry(RedisSession session) {
|
||||
return Instant.ofEpochMilli(session.getLastAccessedTime().toEpochMilli())
|
||||
.plusSeconds(session.getMaxInactiveInterval().getSeconds());
|
||||
}
|
||||
|
||||
private static Map mapOf(Object... objects) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -198,6 +199,13 @@ class RedisHttpsSessionConfigurationTests {
|
||||
Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
registerAndRefresh(RedisConfig.class, ImportConfigAndCustomizeConfiguration.class);
|
||||
RedisSessionRepository sessionRepository = this.context.getBean(RedisSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -261,6 +269,7 @@ class RedisHttpsSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisHttpSession(saveMode = SaveMode.ALWAYS)
|
||||
static class CustomSaveModeExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -342,6 +351,7 @@ class RedisHttpsSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisHttpSession
|
||||
static class SessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@@ -360,4 +370,15 @@ class RedisHttpsSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(RedisHttpSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<RedisSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -27,6 +28,7 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -117,10 +119,8 @@ class RedisIndexedHttpSessionConfigurationTests {
|
||||
void customCleanupCronAnnotation() {
|
||||
registerAndRefresh(RedisConfig.class, CustomCleanupCronExpressionAnnotationConfiguration.class);
|
||||
|
||||
RedisIndexedHttpSessionConfiguration configuration = this.context
|
||||
.getBean(RedisIndexedHttpSessionConfiguration.class);
|
||||
assertThat(configuration).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(configuration, "cleanupCron")).isEqualTo(CLEANUP_CRON_EXPRESSION);
|
||||
RedisIndexedSessionRepository sessionRepository = this.context.getBean(RedisIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("cleanupCron").isEqualTo(CLEANUP_CRON_EXPRESSION);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -229,8 +229,15 @@ class RedisIndexedHttpSessionConfigurationTests {
|
||||
void sessionRepositoryCustomizer() {
|
||||
registerAndRefresh(RedisConfig.class, SessionRepositoryCustomizerConfiguration.class);
|
||||
RedisIndexedSessionRepository sessionRepository = this.context.getBean(RedisIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
registerAndRefresh(RedisConfig.class, ImportConfigAndCustomizeConfiguration.class);
|
||||
RedisIndexedSessionRepository sessionRepository = this.context.getBean(RedisIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
@@ -296,11 +303,13 @@ class RedisIndexedHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisIndexedHttpSession(cleanupCron = CLEANUP_CRON_EXPRESSION)
|
||||
static class CustomCleanupCronExpressionAnnotationConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisIndexedHttpSession(saveMode = SaveMode.ALWAYS)
|
||||
static class CustomSaveModeExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -405,20 +414,32 @@ class RedisIndexedHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisIndexedHttpSession
|
||||
static class SessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
SessionRepositoryCustomizer<RedisIndexedSessionRepository> sessionRepositoryCustomizerOne() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(0);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
SessionRepositoryCustomizer<RedisIndexedSessionRepository> sessionRepositoryCustomizerTwo() {
|
||||
return (sessionRepository) -> sessionRepository
|
||||
.setDefaultMaxInactiveInterval(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
.setDefaultMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(RedisIndexedHttpSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<RedisIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.http.gh109;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -60,7 +61,7 @@ class Gh109Tests {
|
||||
@Configuration
|
||||
static class Config extends RedisHttpSessionConfiguration {
|
||||
|
||||
int sessionTimeout = 100;
|
||||
Duration sessionTimeout = Duration.ofSeconds(100);
|
||||
|
||||
/**
|
||||
* override sessionRepository construction to set the custom session-timeout
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.server;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -25,6 +27,7 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
@@ -102,9 +105,8 @@ class RedisWebSessionConfigurationTests {
|
||||
registerAndRefresh(RedisConfig.class, CustomMaxInactiveIntervalConfig.class);
|
||||
|
||||
ReactiveRedisSessionRepository repository = this.context.getBean(ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -189,7 +191,7 @@ class RedisWebSessionConfigurationTests {
|
||||
void multipleConnectionFactoryRedisConfig() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> registerAndRefresh(RedisConfig.class, MultipleConnectionFactoryRedisConfig.class))
|
||||
.withCauseInstanceOf(NoUniqueBeanDefinitionException.class).havingCause()
|
||||
.havingRootCause().isInstanceOf(NoUniqueBeanDefinitionException.class)
|
||||
.withMessageContaining("expected single matching bean but found 2");
|
||||
}
|
||||
|
||||
@@ -221,8 +223,15 @@ class RedisWebSessionConfigurationTests {
|
||||
void sessionRepositoryCustomizer() {
|
||||
registerAndRefresh(RedisConfig.class, SessionRepositoryCustomizerConfiguration.class);
|
||||
ReactiveRedisSessionRepository sessionRepository = this.context.getBean(ReactiveRedisSessionRepository.class);
|
||||
assertThat(sessionRepository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
registerAndRefresh(RedisConfig.class, ImportConfigAndCustomizeConfiguration.class);
|
||||
ReactiveRedisSessionRepository sessionRepository = this.context.getBean(ReactiveRedisSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
@@ -240,11 +249,13 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class DefaultConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class SpringSessionRedisOperationsResolvingConfig {
|
||||
|
||||
@@ -257,16 +268,19 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession(redisNamespace = REDIS_NAMESPACE)
|
||||
static class CustomNamespaceConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
|
||||
static class CustomMaxInactiveIntervalConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession(saveMode = SaveMode.ALWAYS)
|
||||
static class CustomSaveModeExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -281,6 +295,7 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class QualifiedConnectionFactoryRedisConfig {
|
||||
|
||||
@@ -292,6 +307,7 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class PrimaryConnectionFactoryRedisConfig {
|
||||
|
||||
@@ -303,6 +319,7 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class QualifiedAndPrimaryConnectionFactoryRedisConfig {
|
||||
|
||||
@@ -320,6 +337,7 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class NamedConnectionFactoryRedisConfig {
|
||||
|
||||
@@ -330,6 +348,7 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class MultipleConnectionFactoryRedisConfig {
|
||||
|
||||
@@ -340,6 +359,7 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class CustomRedisSerializerConfig {
|
||||
|
||||
@@ -351,20 +371,32 @@ class RedisWebSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisWebSession
|
||||
static class SessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
ReactiveSessionRepositoryCustomizer<ReactiveRedisSessionRepository> sessionRepositoryCustomizerOne() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(0);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
ReactiveSessionRepositoryCustomizer<ReactiveRedisSessionRepository> sessionRepositoryCustomizerTwo() {
|
||||
return (sessionRepository) -> sessionRepository
|
||||
.setDefaultMaxInactiveInterval(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
.setDefaultMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(RedisWebSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration {
|
||||
|
||||
@Bean
|
||||
ReactiveSessionRepositoryCustomizer<ReactiveRedisSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: ROOT
|
||||
version: '3.0.0-M4'
|
||||
version: '3.0.0-RC2'
|
||||
prerelease: 'true'
|
||||
display_version: '3.0.0-M4'
|
||||
display_version: '3.0.0-RC2'
|
||||
|
||||
@@ -91,6 +91,7 @@ function createSymbolicVersionAlias (component, version, symbolicVersionSegment,
|
||||
|
||||
function computeOut (src, family, version, htmlUrlExtensionStyle) {
|
||||
let { component, module: module_, basename, extname, relative, stem } = src
|
||||
if (component === 'ROOT') component = ''
|
||||
if (module_ === 'ROOT') module_ = ''
|
||||
let indexifyPathSegment = ''
|
||||
let familyPathSegment = ''
|
||||
@@ -120,8 +121,11 @@ function computePub (src, out, family, version, htmlUrlExtensionStyle) {
|
||||
const pub = {}
|
||||
let url
|
||||
if (family === 'nav') {
|
||||
const urlSegments = version ? [src.component, version] : [src.component]
|
||||
if (src.module && src.module !== 'ROOT') urlSegments.push(src.module)
|
||||
const component = src.component || 'ROOT'
|
||||
const urlSegments = component === 'ROOT' ? [] : [component]
|
||||
if (version) urlSegments.push(version)
|
||||
const module_ = src.module || 'ROOT'
|
||||
if (module_ !== 'ROOT') urlSegments.push(module_)
|
||||
// an artificial URL used for resolving page references in navigation model
|
||||
url = '/' + urlSegments.join('/') + '/'
|
||||
pub.moduleRootPath = '.'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,11 +19,13 @@ package docs;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.ReactiveMapSessionRepository;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
|
||||
|
||||
// tag::class[]
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableSpringWebSession
|
||||
public class SpringWebSessionConfig {
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class RememberMeSecurityConfiguration {
|
||||
|
||||
return http
|
||||
.formLogin(Customizer.withDefaults())
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
).build();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- ... -->
|
||||
<security:form-login />
|
||||
<security:remember-me services-ref="rememberMeServices"/>
|
||||
<security:intercept-url pattern="/**" access="permitAll()"/>
|
||||
</security:http>
|
||||
|
||||
<bean id="rememberMeServices"
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*** xref:guides/boot-webflux-custom-cookie.adoc[Custom Cookie]
|
||||
** Java Configuration
|
||||
** XML Configuration
|
||||
* xref:modules.adoc[Modules]
|
||||
* xref:http-session.adoc[HttpSession Integration]
|
||||
* xref:web-socket.adoc[WebSocket Integration]
|
||||
* xref:web-session.adoc[WebSession Integration]
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
[[modules]]
|
||||
= Spring Session Modules
|
||||
|
||||
In Spring Session 1.x, all of the Spring Session's `SessionRepository` implementations were available within the `spring-session` artifact.
|
||||
While convenient, this approach was not sustainable long-term as more features and `SessionRepository` implementations were added to the project.
|
||||
|
||||
With Spring Session 2.0, several modules were split off to be separate modules as well as managed repositories.
|
||||
Spring Session for MongoDB was retired, but was later reactivated as a separate module.
|
||||
As of Spring Session 2.6, Spring Session for MongoDB was merged back into Spring Session.
|
||||
|
||||
Now the situation with the various repositories and modules is as follows:
|
||||
|
||||
* https://github.com/spring-projects/spring-session[`spring-session` repository]
|
||||
** Hosts the Spring Session Core, Spring Session for MongoDB, Spring Session for Redis, Spring Session JDBC, and Spring Session Hazelcast modules.
|
||||
|
||||
* https://github.com/spring-projects/spring-session-data-geode[`spring-session-data-geode` repository]
|
||||
** Hosts the Spring Session Data Geode modules. Spring Session Data Geode has its own user guide, which you can find at the [https://spring.io/projects/spring-session-data-geode#learn site].
|
||||
|
||||
Finally, Spring Session also provides a Maven BOM ("`bill of materials`") module in order to help users with version management concerns:
|
||||
|
||||
* https://github.com/spring-projects/spring-session-bom[`spring-session-bom` repository]
|
||||
** Hosts the Spring Session BOM module
|
||||
@@ -1,4 +1 @@
|
||||
= What's New
|
||||
|
||||
Check also the Spring Session BOM https://github.com/spring-projects/spring-session-bom/wiki#release-notes[release notes]
|
||||
for a list of new and noteworthy features, as well as upgrade instructions for each release.
|
||||
|
||||
@@ -23,7 +23,6 @@ dependencies {
|
||||
testImplementation 'org.assertj:assertj-core'
|
||||
testImplementation 'com.hazelcast:hazelcast'
|
||||
testImplementation 'io.lettuce:lettuce-core'
|
||||
testImplementation 'jakarta.annotation:jakarta.annotation-api'
|
||||
testImplementation 'jakarta.servlet:jakarta.servlet-api'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
|
||||
|
||||
@@ -3,7 +3,6 @@ apply plugin: 'io.spring.convention.spring-module'
|
||||
dependencies {
|
||||
api project(':spring-session-core')
|
||||
api "com.hazelcast:hazelcast"
|
||||
api "jakarta.annotation:jakarta.annotation-api"
|
||||
api "org.springframework:spring-context"
|
||||
|
||||
testImplementation "jakarta.servlet:jakarta.servlet-api"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,9 +26,6 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
@@ -40,6 +37,8 @@ import com.hazelcast.query.Predicates;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.session.DelegatingIndexResolver;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
@@ -116,7 +115,8 @@ import org.springframework.util.Assert;
|
||||
public class HazelcastIndexedSessionRepository
|
||||
implements FindByIndexNameSessionRepository<HazelcastIndexedSessionRepository.HazelcastSession>,
|
||||
EntryAddedListener<String, MapSession>, EntryEvictedListener<String, MapSession>,
|
||||
EntryRemovedListener<String, MapSession>, EntryExpiredListener<String, MapSession> {
|
||||
EntryRemovedListener<String, MapSession>, EntryExpiredListener<String, MapSession>, InitializingBean,
|
||||
DisposableBean {
|
||||
|
||||
/**
|
||||
* The default name of map used by Spring Session to store sessions.
|
||||
@@ -137,11 +137,7 @@ public class HazelcastIndexedSessionRepository
|
||||
private ApplicationEventPublisher eventPublisher = (event) -> {
|
||||
};
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link MapSession#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
|
||||
|
||||
@@ -164,14 +160,14 @@ public class HazelcastIndexedSessionRepository
|
||||
this.hazelcastInstance = hazelcastInstance;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
this.sessions = this.hazelcastInstance.getMap(this.sessionMapName);
|
||||
this.sessionListenerId = this.sessions.addEntryListener(this, true);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void close() {
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.sessions.removeEntryListener(this.sessionListenerId);
|
||||
}
|
||||
|
||||
@@ -190,13 +186,27 @@ public class HazelcastIndexedSessionRepository
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* timeout. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the maximum inactive interval in seconds
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) {
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
|
||||
* @deprecated since 3.0.0, in favor of
|
||||
* {@link #setDefaultMaxInactiveInterval(Duration)}
|
||||
*/
|
||||
@Deprecated(since = "3.0.0")
|
||||
public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) {
|
||||
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link IndexResolver} to use.
|
||||
* @param indexResolver the index resolver
|
||||
@@ -236,9 +246,7 @@ public class HazelcastIndexedSessionRepository
|
||||
@Override
|
||||
public HazelcastSession createSession() {
|
||||
MapSession cached = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
HazelcastSession session = new HazelcastSession(cached, true);
|
||||
session.flushImmediateIfNecessary();
|
||||
return session;
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.lang.annotation.Target;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.MapSession;
|
||||
@@ -41,7 +40,7 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
* {@link HazelcastInstance} must be provided. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @Configuration(proxyBeanMethods = false)
|
||||
* @EnableHazelcastHttpSession
|
||||
* public class HazelcastHttpSessionConfig {
|
||||
*
|
||||
@@ -67,7 +66,6 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(HazelcastHttpSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableHazelcastHttpSession {
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session.hazelcast.config.annotation.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -54,9 +56,10 @@ import org.springframework.util.StringUtils;
|
||||
* @see EnableHazelcastHttpSession
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfiguration implements ImportAware {
|
||||
@Import(SpringHttpSessionConfiguration.class)
|
||||
public class HazelcastHttpSessionConfiguration implements ImportAware {
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private String sessionMapName = HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME;
|
||||
|
||||
@@ -77,8 +80,13 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
|
||||
return createHazelcastIndexedSessionRepository();
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
|
||||
}
|
||||
|
||||
public void setSessionMapName(String sessionMapName) {
|
||||
@@ -125,7 +133,10 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
|
||||
Map<String, Object> attributeMap = importMetadata
|
||||
.getAnnotationAttributes(EnableHazelcastHttpSession.class.getName());
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributeMap);
|
||||
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
|
||||
if (attributes == null) {
|
||||
return;
|
||||
}
|
||||
this.maxInactiveInterval = Duration.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
|
||||
String sessionMapNameValue = attributes.getString("sessionMapName");
|
||||
if (StringUtils.hasText(sessionMapNameValue)) {
|
||||
this.sessionMapName = sessionMapNameValue;
|
||||
@@ -144,7 +155,7 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
|
||||
if (StringUtils.hasText(this.sessionMapName)) {
|
||||
sessionRepository.setSessionMapName(this.sessionMapName);
|
||||
}
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
|
||||
sessionRepository.setFlushMode(this.flushMode);
|
||||
sessionRepository.setSaveMode(this.saveMode);
|
||||
this.sessionRepositoryCustomizers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,7 +76,7 @@ class HazelcastIndexedSessionRepositoryTests {
|
||||
void setUp() {
|
||||
given(this.hazelcastInstance.<String, MapSession>getMap(anyString())).willReturn(this.sessions);
|
||||
this.repository = new HazelcastIndexedSessionRepository(this.hazelcastInstance);
|
||||
this.repository.init();
|
||||
this.repository.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,12 +105,12 @@ class HazelcastIndexedSessionRepositoryTests {
|
||||
void createSessionCustomMaxInactiveInterval() {
|
||||
verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean());
|
||||
|
||||
int interval = 1;
|
||||
Duration interval = Duration.ofSeconds(1);
|
||||
this.repository.setDefaultMaxInactiveInterval(interval);
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
|
||||
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(interval));
|
||||
assertThat(session.getMaxInactiveInterval()).isEqualTo(interval);
|
||||
verifyNoMoreInteractions(this.sessions);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.session.hazelcast.config.annotation.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -27,6 +29,7 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.session.FlushMode;
|
||||
@@ -68,9 +71,8 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
@Test
|
||||
void noHazelcastInstanceConfiguration() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> registerAndRefresh(NoHazelcastInstanceConfiguration.class))
|
||||
.withCauseInstanceOf(NoSuchBeanDefinitionException.class).havingCause()
|
||||
.withMessageContaining("HazelcastInstance");
|
||||
.isThrownBy(() -> registerAndRefresh(NoHazelcastInstanceConfiguration.class)).havingRootCause()
|
||||
.isInstanceOf(NoSuchBeanDefinitionException.class).withMessageContaining("HazelcastInstance");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,9 +107,8 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
registerAndRefresh(BaseConfiguration.class, CustomMaxInactiveIntervalInSecondsSetConfiguration.class);
|
||||
|
||||
HazelcastIndexedSessionRepository repository = this.context.getBean(HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,9 +116,8 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
registerAndRefresh(CustomMaxInactiveIntervalInSecondsConfiguration.class);
|
||||
|
||||
HazelcastIndexedSessionRepository repository = this.context.getBean(HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -205,8 +205,8 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
@Test
|
||||
void multipleHazelcastInstanceConfiguration() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> registerAndRefresh(MultipleHazelcastInstanceConfiguration.class))
|
||||
.withCauseInstanceOf(NoUniqueBeanDefinitionException.class).havingCause()
|
||||
.isThrownBy(() -> registerAndRefresh(MultipleHazelcastInstanceConfiguration.class)).havingRootCause()
|
||||
.isInstanceOf(NoUniqueBeanDefinitionException.class)
|
||||
.withMessageContaining("expected single matching bean but found 2");
|
||||
}
|
||||
|
||||
@@ -226,8 +226,16 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
registerAndRefresh(SessionRepositoryCustomizerConfiguration.class);
|
||||
HazelcastIndexedSessionRepository sessionRepository = this.context
|
||||
.getBean(HazelcastIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
registerAndRefresh(ImportConfigAndCustomizeConfiguration.class);
|
||||
HazelcastIndexedSessionRepository sessionRepository = this.context
|
||||
.getBean(HazelcastIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
@@ -280,7 +288,7 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
static class CustomMaxInactiveIntervalInSecondsSetConfiguration extends HazelcastHttpSessionConfiguration {
|
||||
|
||||
CustomMaxInactiveIntervalInSecondsSetConfiguration() {
|
||||
setMaxInactiveIntervalInSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
setMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -300,6 +308,7 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableHazelcastHttpSession(saveMode = SaveMode.ALWAYS)
|
||||
static class CustomSaveModeExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -414,6 +423,7 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableHazelcastHttpSession
|
||||
static class CustomIndexResolverConfiguration extends BaseConfiguration {
|
||||
|
||||
@@ -425,20 +435,32 @@ class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableHazelcastHttpSession
|
||||
static class SessionRepositoryCustomizerConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
SessionRepositoryCustomizer<HazelcastIndexedSessionRepository> sessionRepositoryCustomizerOne() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(0);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
SessionRepositoryCustomizer<HazelcastIndexedSessionRepository> sessionRepositoryCustomizerTwo() {
|
||||
return (sessionRepository) -> sessionRepository
|
||||
.setDefaultMaxInactiveInterval(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
.setDefaultMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(HazelcastHttpSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<HazelcastIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ dependencies {
|
||||
testImplementation "org.springframework:spring-web"
|
||||
testImplementation "org.springframework.security:spring-security-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine"
|
||||
|
||||
integrationTestCompile "com.h2database:h2"
|
||||
@@ -24,6 +25,7 @@ dependencies {
|
||||
integrationTestCompile "com.zaxxer:HikariCP"
|
||||
integrationTestCompile "mysql:mysql-connector-java"
|
||||
integrationTestCompile "org.apache.derby:derby"
|
||||
integrationTestCompile "org.apache.derby:derbytools"
|
||||
integrationTestCompile "org.hsqldb:hsqldb"
|
||||
integrationTestCompile "org.mariadb.jdbc:mariadb-java-client"
|
||||
integrationTestCompile "org.postgresql:postgresql"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2020 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -827,6 +828,7 @@ abstract class AbstractJdbcIndexedSessionRepositoryITests {
|
||||
return this.changedContext.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class BaseConfig {
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import java.util.stream.Collectors;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
@@ -48,6 +50,10 @@ import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.scheduling.support.CronExpression;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import org.springframework.session.DelegatingIndexResolver;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.FlushMode;
|
||||
@@ -130,14 +136,19 @@ import org.springframework.util.StringUtils;
|
||||
* @author Craig Andrews
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class JdbcIndexedSessionRepository
|
||||
implements FindByIndexNameSessionRepository<JdbcIndexedSessionRepository.JdbcSession> {
|
||||
public class JdbcIndexedSessionRepository implements
|
||||
FindByIndexNameSessionRepository<JdbcIndexedSessionRepository.JdbcSession>, InitializingBean, DisposableBean {
|
||||
|
||||
/**
|
||||
* The default name of database table used by Spring Session to store sessions.
|
||||
*/
|
||||
public static final String DEFAULT_TABLE_NAME = "SPRING_SESSION";
|
||||
|
||||
/**
|
||||
* The default cron expression used for expired session cleanup job.
|
||||
*/
|
||||
public static final String DEFAULT_CLEANUP_CRON = "0 * * * * *";
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
private static final String CREATE_SESSION_QUERY = """
|
||||
@@ -225,11 +236,7 @@ public class JdbcIndexedSessionRepository
|
||||
|
||||
private String deleteSessionsByExpiryTimeQuery;
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override the default value for
|
||||
* {@link JdbcSession#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
private Duration defaultMaxInactiveInterval = Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
|
||||
|
||||
@@ -241,6 +248,10 @@ public class JdbcIndexedSessionRepository
|
||||
|
||||
private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
|
||||
|
||||
private String cleanupCron = DEFAULT_CLEANUP_CRON;
|
||||
|
||||
private ThreadPoolTaskScheduler taskScheduler;
|
||||
|
||||
/**
|
||||
* Create a new {@link JdbcIndexedSessionRepository} instance which uses the provided
|
||||
* {@link JdbcOperations} and {@link TransactionOperations} to manage sessions.
|
||||
@@ -255,6 +266,28 @@ public class JdbcIndexedSessionRepository
|
||||
prepareQueries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (!Scheduled.CRON_DISABLED.equals(this.cleanupCron)) {
|
||||
this.taskScheduler = createTaskScheduler();
|
||||
this.taskScheduler.initialize();
|
||||
this.taskScheduler.schedule(this::cleanUpExpiredSessions, new CronTrigger(this.cleanupCron));
|
||||
}
|
||||
}
|
||||
|
||||
private static ThreadPoolTaskScheduler createTaskScheduler() {
|
||||
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||
taskScheduler.setThreadNamePrefix("spring-session-");
|
||||
return taskScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.taskScheduler != null) {
|
||||
this.taskScheduler.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of database table used to store sessions.
|
||||
* @param tableName the database table name
|
||||
@@ -349,13 +382,27 @@ public class JdbcIndexedSessionRepository
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* timeout. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the maximum inactive interval in seconds
|
||||
* time out. The default is 30 minutes.
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) {
|
||||
public void setDefaultMaxInactiveInterval(Duration defaultMaxInactiveInterval) {
|
||||
Assert.notNull(defaultMaxInactiveInterval, "defaultMaxInactiveInterval must not be null");
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum inactive interval in seconds between requests before newly created
|
||||
* sessions will be invalidated. A negative time indicates that the session will never
|
||||
* time out. The default is 1800 (30 minutes).
|
||||
* @param defaultMaxInactiveInterval the default maxInactiveInterval in seconds
|
||||
* @deprecated since 3.0.0, in favor of
|
||||
* {@link #setDefaultMaxInactiveInterval(Duration)}
|
||||
*/
|
||||
@Deprecated(since = "3.0.0")
|
||||
public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) {
|
||||
setDefaultMaxInactiveInterval(Duration.ofSeconds(defaultMaxInactiveInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link IndexResolver} to use.
|
||||
* @param indexResolver the index resolver
|
||||
@@ -397,12 +444,25 @@ public class JdbcIndexedSessionRepository
|
||||
this.saveMode = saveMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cleanup cron expression.
|
||||
* @param cleanupCron the cleanup cron expression
|
||||
* @since 3.0.0
|
||||
* @see CronExpression
|
||||
* @see Scheduled#CRON_DISABLED
|
||||
*/
|
||||
public void setCleanupCron(String cleanupCron) {
|
||||
Assert.notNull(cleanupCron, "cleanupCron must not be null");
|
||||
if (!Scheduled.CRON_DISABLED.equals(cleanupCron)) {
|
||||
Assert.isTrue(CronExpression.isValidExpression(cleanupCron), "cleanupCron must be valid");
|
||||
}
|
||||
this.cleanupCron = cleanupCron;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcSession createSession() {
|
||||
MapSession delegate = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
delegate.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
delegate.setMaxInactiveInterval(this.defaultMaxInactiveInterval);
|
||||
JdbcSession session = new JdbcSession(delegate, UUID.randomUUID().toString(), true);
|
||||
session.flushIfRequired();
|
||||
return session;
|
||||
|
||||
@@ -32,7 +32,26 @@ class SessionJdbcRuntimeHints implements RuntimeHintsRegistrar {
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
hints.reflection().registerType(TypeReference.of("javax.sql.DataSource"),
|
||||
(hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS));
|
||||
hints.resources().registerPattern("org/springframework/session/jdbc/*.sql");
|
||||
hints.resources().registerPattern("org/springframework/session/jdbc/schema-db2.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-derby.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-db2.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-derby.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-h2.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-hsqldb.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-mysql.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-oracle.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-postgresql.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-sqlite.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-sqlserver.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-drop-sybase.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-h2.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-hsqldb.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-mysql.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-oracle.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-postgresql.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-sqlite.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-sqlserver.sql")
|
||||
.registerPattern("org/springframework/session/jdbc/schema-sybase.sql");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,7 +24,6 @@ import java.lang.annotation.Target;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.MapSession;
|
||||
@@ -42,7 +41,7 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
* {@link DataSource} must be provided. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @Configuration(proxyBeanMethods = false)
|
||||
* @EnableJdbcHttpSession
|
||||
* public class JdbcHttpSessionConfig {
|
||||
*
|
||||
@@ -77,7 +76,6 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(JdbcHttpSessionConfiguration.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public @interface EnableJdbcHttpSession {
|
||||
|
||||
/**
|
||||
@@ -98,7 +96,7 @@ public @interface EnableJdbcHttpSession {
|
||||
* @return the session cleanup cron expression
|
||||
* @since 2.0.0
|
||||
*/
|
||||
String cleanupCron() default JdbcHttpSessionConfiguration.DEFAULT_CLEANUP_CRON;
|
||||
String cleanupCron() default JdbcIndexedSessionRepository.DEFAULT_CLEANUP_CRON;
|
||||
|
||||
/**
|
||||
* Flush mode for the sessions. The default is {@code ON_SAVE} which only updates the
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.session.jdbc.config.annotation.web.http;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
@@ -43,9 +45,6 @@ import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.IndexResolver;
|
||||
import org.springframework.session.MapSession;
|
||||
@@ -77,16 +76,14 @@ import org.springframework.util.StringValueResolver;
|
||||
* @see EnableJdbcHttpSession
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
@Import(SpringHttpSessionConfiguration.class)
|
||||
public class JdbcHttpSessionConfiguration implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
|
||||
|
||||
static final String DEFAULT_CLEANUP_CRON = "0 * * * * *";
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
private Duration maxInactiveInterval = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL;
|
||||
|
||||
private String tableName = JdbcIndexedSessionRepository.DEFAULT_TABLE_NAME;
|
||||
|
||||
private String cleanupCron = DEFAULT_CLEANUP_CRON;
|
||||
private String cleanupCron = JdbcIndexedSessionRepository.DEFAULT_CLEANUP_CRON;
|
||||
|
||||
private FlushMode flushMode = FlushMode.ON_SAVE;
|
||||
|
||||
@@ -123,9 +120,10 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
if (StringUtils.hasText(this.tableName)) {
|
||||
sessionRepository.setTableName(this.tableName);
|
||||
}
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveInterval);
|
||||
sessionRepository.setFlushMode(this.flushMode);
|
||||
sessionRepository.setSaveMode(this.saveMode);
|
||||
sessionRepository.setCleanupCron(this.cleanupCron);
|
||||
if (this.indexResolver != null) {
|
||||
sessionRepository.setIndexResolver(this.indexResolver);
|
||||
}
|
||||
@@ -162,8 +160,13 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
setMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
@@ -247,7 +250,10 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
Map<String, Object> attributeMap = importMetadata
|
||||
.getAnnotationAttributes(EnableJdbcHttpSession.class.getName());
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributeMap);
|
||||
this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds");
|
||||
if (attributes == null) {
|
||||
return;
|
||||
}
|
||||
this.maxInactiveInterval = Duration.ofSeconds(attributes.<Integer>getNumber("maxInactiveIntervalInSeconds"));
|
||||
String tableNameValue = attributes.getString("tableName");
|
||||
if (StringUtils.hasText(tableNameValue)) {
|
||||
this.tableName = this.embeddedValueResolver.resolveStringValue(tableNameValue);
|
||||
@@ -281,25 +287,4 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of scheduled job for cleaning up expired sessions.
|
||||
*/
|
||||
@EnableScheduling
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class SessionCleanupConfiguration implements SchedulingConfigurer {
|
||||
|
||||
private final JdbcIndexedSessionRepository sessionRepository;
|
||||
|
||||
SessionCleanupConfiguration(JdbcIndexedSessionRepository sessionRepository) {
|
||||
this.sessionRepository = sessionRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||
taskRegistrar.addCronTask(this.sessionRepository::cleanUpExpiredSessions,
|
||||
JdbcHttpSessionConfiguration.this.cleanupCron);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.TemporaryLobCreator;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
@@ -243,6 +244,25 @@ class JdbcIndexedSessionRepositoryTests {
|
||||
.withMessage("saveMode must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCleanupCronNull() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCleanupCron(null))
|
||||
.withMessage("cleanupCron must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCleanupCronInvalid() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCleanupCron("test"))
|
||||
.withMessage("cleanupCron must be valid");
|
||||
}
|
||||
|
||||
@Test
|
||||
void setCleanupCronDisabled() {
|
||||
this.repository.setCleanupCron(Scheduled.CRON_DISABLED);
|
||||
this.repository.afterPropertiesSet();
|
||||
assertThat(this.repository).extracting("taskScheduler").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createSessionDefaultMaxInactiveInterval() {
|
||||
JdbcSession session = this.repository.createSession();
|
||||
@@ -254,13 +274,13 @@ class JdbcIndexedSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
void createSessionCustomMaxInactiveInterval() {
|
||||
int interval = 1;
|
||||
Duration interval = Duration.ofSeconds(1);
|
||||
this.repository.setDefaultMaxInactiveInterval(interval);
|
||||
|
||||
JdbcSession session = this.repository.createSession();
|
||||
|
||||
assertThat(session.isNew()).isTrue();
|
||||
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(interval));
|
||||
assertThat(session.getMaxInactiveInterval()).isEqualTo(interval);
|
||||
verifyNoMoreInteractions(this.jdbcOperations);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,20 @@
|
||||
|
||||
package org.springframework.session.jdbc.aot.hint;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -45,13 +53,21 @@ class SessionJdbcRuntimeHintsTests {
|
||||
assertThat(match).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void jdbcSchemasHasHints() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("getSchemaFileNames")
|
||||
void jdbcSchemasHasHints(String schemaFileName) {
|
||||
this.sessionJdbcRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
|
||||
assertThat(RuntimeHintsPredicates.resource().forResource("org/springframework/session/jdbc/schema.sql"))
|
||||
assertThat(RuntimeHintsPredicates.resource().forResource("org/springframework/session/jdbc/" + schemaFileName))
|
||||
.accepts(this.hints);
|
||||
}
|
||||
|
||||
private static Stream<String> getSchemaFileNames() throws IOException {
|
||||
return Arrays
|
||||
.stream(new PathMatchingResourcePatternResolver()
|
||||
.getResources("classpath*:org/springframework/session/jdbc/schema-*.sql"))
|
||||
.map(Resource::getFilename);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dataSourceHasHints() {
|
||||
this.sessionJdbcRuntimeHints.registerHints(this.hints, getClass().getClassLoader());
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.session.jdbc.config.annotation.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -27,6 +29,7 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -117,9 +120,8 @@ class JdbcHttpSessionConfigurationTests {
|
||||
CustomMaxInactiveIntervalInSecondsAnnotationConfiguration.class);
|
||||
|
||||
JdbcIndexedSessionRepository repository = this.context.getBean(JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,27 +129,24 @@ class JdbcHttpSessionConfigurationTests {
|
||||
registerAndRefresh(DataSourceConfiguration.class, CustomMaxInactiveIntervalInSecondsSetterConfiguration.class);
|
||||
|
||||
JdbcIndexedSessionRepository repository = this.context.getBean(JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(repository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customCleanupCronAnnotation() {
|
||||
registerAndRefresh(DataSourceConfiguration.class, CustomCleanupCronExpressionAnnotationConfiguration.class);
|
||||
|
||||
JdbcHttpSessionConfiguration configuration = this.context.getBean(JdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(configuration, "cleanupCron")).isEqualTo(CLEANUP_CRON_EXPRESSION);
|
||||
JdbcIndexedSessionRepository repository = this.context.getBean(JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).extracting("cleanupCron").isEqualTo(CLEANUP_CRON_EXPRESSION);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customCleanupCronSetter() {
|
||||
registerAndRefresh(DataSourceConfiguration.class, CustomCleanupCronExpressionSetterConfiguration.class);
|
||||
|
||||
JdbcHttpSessionConfiguration configuration = this.context.getBean(JdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(configuration, "cleanupCron")).isEqualTo(CLEANUP_CRON_EXPRESSION);
|
||||
JdbcIndexedSessionRepository repository = this.context.getBean(JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).extracting("cleanupCron").isEqualTo(CLEANUP_CRON_EXPRESSION);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -298,8 +297,8 @@ class JdbcHttpSessionConfigurationTests {
|
||||
void sessionRepositoryCustomizer() {
|
||||
registerAndRefresh(DataSourceConfiguration.class, SessionRepositoryCustomizerConfiguration.class);
|
||||
JdbcIndexedSessionRepository sessionRepository = this.context.getBean(JdbcIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval")
|
||||
.isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -312,11 +311,19 @@ class JdbcHttpSessionConfigurationTests {
|
||||
assertThat(jdbcTemplate.getExceptionTranslator()).isInstanceOf(SQLErrorCodeSQLExceptionTranslator.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void importConfigAndCustomize() {
|
||||
registerAndRefresh(DataSourceConfiguration.class, ImportConfigAndCustomizeConfiguration.class);
|
||||
JdbcIndexedSessionRepository sessionRepository = this.context.getBean(JdbcIndexedSessionRepository.class);
|
||||
assertThat(sessionRepository).extracting("defaultMaxInactiveInterval").isEqualTo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class NoDataSourceConfiguration {
|
||||
|
||||
@@ -337,11 +344,13 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession(tableName = TABLE_NAME)
|
||||
static class CustomTableNameAnnotationConfiguration {
|
||||
|
||||
@@ -356,6 +365,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
|
||||
static class CustomMaxInactiveIntervalInSecondsAnnotationConfiguration {
|
||||
|
||||
@@ -370,6 +380,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession(cleanupCron = CLEANUP_CRON_EXPRESSION)
|
||||
static class CustomCleanupCronExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -384,6 +395,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession(flushMode = FlushMode.IMMEDIATE)
|
||||
static class CustomFlushModeExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -398,6 +410,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession(saveMode = SaveMode.ALWAYS)
|
||||
static class CustomSaveModeExpressionAnnotationConfiguration {
|
||||
|
||||
@@ -412,6 +425,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class QualifiedDataSourceConfiguration {
|
||||
|
||||
@@ -423,6 +437,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class PrimaryDataSourceConfiguration {
|
||||
|
||||
@@ -434,6 +449,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class QualifiedAndPrimaryDataSourceConfiguration {
|
||||
|
||||
@@ -451,6 +467,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class NamedDataSourceConfiguration {
|
||||
|
||||
@@ -461,6 +478,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class MultipleDataSourceConfiguration {
|
||||
|
||||
@@ -471,6 +489,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class CustomTransactionOperationsConfiguration {
|
||||
|
||||
@@ -481,6 +500,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class CustomIndexResolverConfiguration {
|
||||
|
||||
@@ -492,6 +512,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class CustomLobHandlerConfiguration {
|
||||
|
||||
@@ -502,6 +523,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class CustomConversionServiceConfiguration {
|
||||
|
||||
@@ -512,6 +534,7 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession(tableName = "${session.jdbc.tableName}")
|
||||
static class CustomJdbcHttpSessionConfiguration {
|
||||
|
||||
@@ -522,20 +545,32 @@ class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession
|
||||
static class SessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
SessionRepositoryCustomizer<JdbcIndexedSessionRepository> sessionRepositoryCustomizerOne() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(0);
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
SessionRepositoryCustomizer<JdbcIndexedSessionRepository> sessionRepositoryCustomizerTwo() {
|
||||
return (sessionRepository) -> sessionRepository
|
||||
.setDefaultMaxInactiveInterval(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
.setDefaultMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(JdbcHttpSessionConfiguration.class)
|
||||
static class ImportConfigAndCustomizeConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<JdbcIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (sessionRepository) -> sessionRepository.setDefaultMaxInactiveInterval(Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
spring.security.user.password=password
|
||||
spring.session.redis.repository-type=indexed
|
||||
|
||||
@@ -35,7 +35,7 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,10 +19,12 @@ package org.springframework.session.mongodb.examples.config;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
|
||||
|
||||
// tag::class[]
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableMongoHttpSession // <1>
|
||||
public class HttpSessionConfig {
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ public class WebSecurityConfig {
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,12 +17,14 @@
|
||||
package sample;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
import org.springframework.session.web.http.CookieSerializer;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(EmbeddedRedisConfig.class)
|
||||
@EnableRedisHttpSession
|
||||
public class Config {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package sample;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHtt
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
// tag::class[]
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJdbcHttpSession // <1>
|
||||
public class Config {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,12 +17,14 @@
|
||||
package sample;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
|
||||
@Import(EmbeddedRedisConfig.class)
|
||||
// tag::class[]
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRedisHttpSession // <1>
|
||||
public class Config {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user