Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56033a9b68 | ||
|
|
99a2b079ac | ||
|
|
9120151692 | ||
|
|
5abbe66b1d | ||
|
|
f00c196430 | ||
|
|
be2604ca69 | ||
|
|
2aa71ffb6d | ||
|
|
8bdcba6e50 | ||
|
|
8dd1a10f1b | ||
|
|
1d247aa96f | ||
|
|
c00d6a7bf2 | ||
|
|
c0df3bf28b | ||
|
|
1b8c9838a4 | ||
|
|
8a1b454121 | ||
|
|
ef69c8169a | ||
|
|
40b3d07224 | ||
|
|
8c726f2215 | ||
|
|
c2a86a27ce | ||
|
|
6a08ef6f97 | ||
|
|
9c4e20f074 | ||
|
|
5845a9c46a | ||
|
|
7c6693a268 | ||
|
|
05a3f59813 | ||
|
|
47a7a35aa4 | ||
|
|
04b4fe3e3b | ||
|
|
36bb65e4b5 | ||
|
|
8ef36e4f3e | ||
|
|
ab3e280993 | ||
|
|
30562b5749 | ||
|
|
d42a7b65ea | ||
|
|
db9807d12b | ||
|
|
db09fa8168 | ||
|
|
031541bc05 | ||
|
|
084e3428fb | ||
|
|
b321ff02f0 | ||
|
|
c6c6beb40c | ||
|
|
0127ef9f9b | ||
|
|
cd8686ae9c | ||
|
|
233d179bfa | ||
|
|
4e8ae8d9d4 | ||
|
|
8c6810c6dd | ||
|
|
fca411996a | ||
|
|
79b8296e1c | ||
|
|
043cb42149 | ||
|
|
c28f047eb5 | ||
|
|
972cf66d7e | ||
|
|
f1319483ee | ||
|
|
6ad5006280 | ||
|
|
f7e07b7f6b | ||
|
|
4cf26d9c36 | ||
|
|
a848df1235 | ||
|
|
f8292ba512 | ||
|
|
21bcc6e8d7 | ||
|
|
905a77a3a8 | ||
|
|
295f9f78c3 | ||
|
|
04ecc82d09 | ||
|
|
2ddd9e58a3 | ||
|
|
3c52298c47 | ||
|
|
7b385c7d33 | ||
|
|
87d51c54c9 | ||
|
|
210e8eebc5 | ||
|
|
7d52c87173 | ||
|
|
e3c6fb67f2 | ||
|
|
79f187ddd6 | ||
|
|
22f4b0bc9d | ||
|
|
c5ea626d03 | ||
|
|
d067cd1e66 | ||
|
|
76a6be572a |
@@ -16,4 +16,5 @@ cache:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
script: ./gradlew build
|
||||
install: true
|
||||
script: ./gradlew clean build --refresh-dependencies --no-daemon
|
||||
|
||||
29
Jenkinsfile
vendored
29
Jenkinsfile
vendored
@@ -24,21 +24,6 @@ try {
|
||||
}
|
||||
}
|
||||
},
|
||||
sonar: {
|
||||
stage('Sonar') {
|
||||
node {
|
||||
checkout scm
|
||||
withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) {
|
||||
try {
|
||||
sh "./gradlew clean sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: sonar'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
springio: {
|
||||
stage('Spring IO') {
|
||||
node {
|
||||
@@ -56,7 +41,17 @@ try {
|
||||
}
|
||||
|
||||
if(currentBuild.result == 'SUCCESS') {
|
||||
parallel docs: {
|
||||
parallel artifactory: {
|
||||
stage('Artifactory Deploy') {
|
||||
node {
|
||||
checkout scm
|
||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||
sh "./gradlew artifactoryPublish -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --no-daemon --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
stage('Deploy Docs') {
|
||||
node {
|
||||
checkout scm
|
||||
@@ -85,7 +80,7 @@ try {
|
||||
subject: subject,
|
||||
body: details,
|
||||
recipientProviders: RECIPIENTS,
|
||||
to: "$SPRING_SECURITY_TEAM_EMAILS"
|
||||
to: "$SPRING_SESSION_TEAM_EMAILS"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath 'io.spring.gradle:spring-build-conventions:0.0.1.RELEASE'
|
||||
classpath 'io.spring.gradle:spring-build-conventions:0.0.3.RELEASE'
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
|
||||
}
|
||||
repositories {
|
||||
maven { url 'https://repo.spring.io/libs-snapshot' }
|
||||
maven { url 'https://repo.spring.io/plugins-snapshot' }
|
||||
maven { url 'https://repo.spring.io/plugins-release' }
|
||||
}
|
||||
}
|
||||
apply plugin: 'io.spring.convention.root'
|
||||
|
||||
@@ -2,8 +2,10 @@ apply plugin: 'io.spring.convention.docs'
|
||||
apply plugin: 'io.spring.convention.spring-test'
|
||||
|
||||
dependencies {
|
||||
testCompile project(':spring-session')
|
||||
testCompile project(':spring-session-core')
|
||||
testCompile project(':spring-session-data-redis')
|
||||
testCompile project(':spring-session-hazelcast')
|
||||
testCompile project(':spring-session-jdbc')
|
||||
testCompile "org.springframework:spring-jdbc"
|
||||
testCompile "org.springframework:spring-messaging"
|
||||
testCompile "org.springframework:spring-webmvc"
|
||||
@@ -39,5 +41,5 @@ asciidoctor {
|
||||
'docs-test-dir' : rootProject.projectDir.path + '/docs/src/test/java/',
|
||||
'docs-test-resources-dir' : rootProject.projectDir.path + '/docs/src/test/resources/',
|
||||
'samples-dir' : rootProject.projectDir.path + '/samples/',
|
||||
'session-main-resources-dir' : rootProject.projectDir.path + '/spring-session/src/main/resources/'
|
||||
'session-jdbc-main-resources-dir' : project(':spring-session-jdbc').projectDir.path + '/src/main/resources/'
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ include::{docs-test-dir}docs/security/SecurityConfiguration.java[tags=class]
|
||||
----
|
||||
|
||||
This assumes that you've also configured Spring Session to provide a `FindByIndexNameSessionRepository` that
|
||||
returns `ExpiringSession` instances.
|
||||
returns `Session` instances.
|
||||
|
||||
When using XML configuration, it would look something like this:
|
||||
[source,xml,indent=0]
|
||||
@@ -458,11 +458,7 @@ include::{indexdoc-tests}[tags=repository-demo]
|
||||
<5> We retrieve the `Session` from the `SessionRepository`.
|
||||
<6> We obtain the persisted `User` from our `Session` without the need for explicitly casting our attribute.
|
||||
|
||||
[[api-expiringsession]]
|
||||
=== ExpiringSession
|
||||
|
||||
An `ExpiringSession` extends a `Session` by providing attributes related to the `Session` instance's expiration.
|
||||
If there is no need to interact with the expiration information, prefer using the more simple `Session` API.
|
||||
`Session` API also provides attributes related to the `Session` instance's expiration.
|
||||
|
||||
Typical usage might look like the following:
|
||||
|
||||
@@ -471,17 +467,17 @@ Typical usage might look like the following:
|
||||
include::{indexdoc-tests}[tags=expire-repository-demo]
|
||||
----
|
||||
|
||||
<1> We create a `SessionRepository` instance with a generic type, `S`, that extends `ExpiringSession`. The generic type is defined in our class.
|
||||
<2> We create a new `ExpiringSession` using our `SessionRepository` and assign it to a variable of type `S`.
|
||||
<3> We interact with the `ExpiringSession`.
|
||||
In our example, we demonstrate updating the amount of time the `ExpiringSession` can be inactive before it expires.
|
||||
<4> We now save the `ExpiringSession`.
|
||||
<1> We create a `SessionRepository` instance with a generic type, `S`, that extends `Session`. The generic type is defined in our class.
|
||||
<2> We create a new `Session` using our `SessionRepository` and assign it to a variable of type `S`.
|
||||
<3> We interact with the `Session`.
|
||||
In our example, we demonstrate updating the amount of time the `Session` can be inactive before it expires.
|
||||
<4> We now save the `Session`.
|
||||
This is why we needed the generic type `S`.
|
||||
The `SessionRepository` only allows saving `ExpiringSession` instances that were created or retrieved using the same `SessionRepository`.
|
||||
The `SessionRepository` only allows saving `Session` instances that were created or retrieved using the same `SessionRepository`.
|
||||
This allows for the `SessionRepository` to make implementation specific optimizations (i.e. only writing attributes that have changed).
|
||||
The last accessed time is automatically updated when the `ExpiringSession` is saved.
|
||||
<5> We retrieve the `ExpiringSession` from the `SessionRepository`.
|
||||
If the `ExpiringSession` were expired, the result would be null.
|
||||
The last accessed time is automatically updated when the `Session` is saved.
|
||||
<5> We retrieve the `Session` from the `SessionRepository`.
|
||||
If the `Session` were expired, the result would be null.
|
||||
|
||||
[[api-sessionrepository]]
|
||||
=== SessionRepository
|
||||
@@ -640,7 +636,7 @@ HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe sessionAttr:a
|
||||
[[api-redisoperationssessionrepository-expiration]]
|
||||
===== Session Expiration
|
||||
|
||||
An expiration is associated to each session using the EXPIRE command based upon the `ExpiringSession.getMaxInactiveInterval()`.
|
||||
An expiration is associated to each session using the EXPIRE command based upon the `Session.getMaxInactiveInterval()`.
|
||||
For example:
|
||||
|
||||
----
|
||||
@@ -653,7 +649,7 @@ An expiration is set on the session itself five minutes after it actually expire
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The `SessionRepository.getSession(String)` method ensures that no expired sessions will be returned.
|
||||
The `SessionRepository.findById(String)` method ensures that no expired sessions will be returned.
|
||||
This means there is no need to check the expiration before using a session.
|
||||
====
|
||||
|
||||
@@ -776,7 +772,7 @@ redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed
|
||||
[[api-mapsessionrepository]]
|
||||
=== MapSessionRepository
|
||||
|
||||
The `MapSessionRepository` allows for persisting `ExpiringSession` in a `Map` with the key being the `ExpiringSession` id and the value being the `ExpiringSession`.
|
||||
The `MapSessionRepository` allows for persisting `Session` in a `Map` with the key being the `Session` id and the value being the `Session`.
|
||||
The implementation can be used with a `ConcurrentHashMap` as a testing or convenience mechanism.
|
||||
Alternatively, it can be used with distributed `Map` implementations. For example, it can be used with Hazelcast.
|
||||
|
||||
@@ -860,14 +856,14 @@ For example, with PostgreSQL database you would use the following schema script:
|
||||
|
||||
[source,sql,indent=0]
|
||||
----
|
||||
include::{session-main-resources-dir}org/springframework/session/jdbc/schema-postgresql.sql[]
|
||||
include::{session-jdbc-main-resources-dir}org/springframework/session/jdbc/schema-postgresql.sql[]
|
||||
----
|
||||
|
||||
And with MySQL database:
|
||||
|
||||
[source,sql,indent=0]
|
||||
----
|
||||
include::{session-main-resources-dir}org/springframework/session/jdbc/schema-mysql.sql[]
|
||||
include::{session-jdbc-main-resources-dir}org/springframework/session/jdbc/schema-mysql.sql[]
|
||||
----
|
||||
|
||||
==== Transaction management
|
||||
@@ -962,19 +958,28 @@ Spring Session is Open Source software released under the http://www.apache.org/
|
||||
|
||||
[[community-extensions]]
|
||||
=== Community Extensions
|
||||
https://github.com/maseev/spring-session-orientdb[Spring Session OrientDB]
|
||||
http://infinispan.org/docs/dev/user_guide/user_guide.html#externalizing_session_using_spring_session[Spring Session Infinispan]
|
||||
|
||||
|===
|
||||
| Name | Location
|
||||
|
||||
| Spring Session OrientDB
|
||||
| https://github.com/maseev/spring-session-orientdb
|
||||
|
||||
| Spring Session Infinispan
|
||||
| http://infinispan.org/docs/dev/user_guide/user_guide.html#externalizing_session_using_spring_session
|
||||
|
||||
|===
|
||||
|
||||
[[minimum-requirements]]
|
||||
== Minimum Requirements
|
||||
|
||||
The minimum requirements for Spring Session are:
|
||||
|
||||
* Java 5+
|
||||
* If you are running in a Servlet Container (not required), Servlet 2.5+
|
||||
* If you are using other Spring libraries (not required), the minimum required version is Spring 3.2.14.
|
||||
While we re-run all unit tests against Spring 3.2.x, we recommend using the latest Spring 4.x version when possible.
|
||||
* Java 8+
|
||||
* If you are running in a Servlet Container (not required), Servlet 3.1+
|
||||
* If you are using other Spring libraries (not required), the minimum required version is Spring 5.0.x.
|
||||
* `@EnableRedisHttpSession` requires Redis 2.8+. This is necessary to support <<api-redisoperationssessionrepository-expiration,Session Expiration>>
|
||||
* `@EnableHazelcastHttpSession` requires Hazelcast 3.6+. This is necessary to support <<api-enablehazelcasthttpsession-storage,`FindByIndexNameSessionRepository`>>
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2017 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,7 +21,7 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@@ -38,7 +38,7 @@ import static org.mockito.Mockito.mock;
|
||||
@WebAppConfiguration
|
||||
public class HttpSessionConfigurationNoOpConfigureRedisActionXmlTests {
|
||||
@Autowired
|
||||
SessionRepositoryFilter<? extends ExpiringSession> filter;
|
||||
SessionRepositoryFilter<? extends Session> filter;
|
||||
|
||||
@Test
|
||||
public void redisConnectionFactoryNotUsedSinceNoValidation() {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package docs;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
@@ -26,7 +28,6 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
@@ -49,7 +50,7 @@ public class IndexDocTests {
|
||||
|
||||
@Test
|
||||
public void repositoryDemo() {
|
||||
RepositoryDemo<ExpiringSession> demo = new RepositoryDemo<>();
|
||||
RepositoryDemo<MapSession> demo = new RepositoryDemo<>();
|
||||
demo.repository = new MapSessionRepository();
|
||||
|
||||
demo.demo();
|
||||
@@ -68,7 +69,7 @@ public class IndexDocTests {
|
||||
|
||||
this.repository.save(toSave); // <4>
|
||||
|
||||
S session = this.repository.getSession(toSave.getId()); // <5>
|
||||
S session = this.repository.findById(toSave.getId()); // <5>
|
||||
|
||||
// <6>
|
||||
User user = session.getAttribute(ATTR_USER);
|
||||
@@ -81,24 +82,24 @@ public class IndexDocTests {
|
||||
|
||||
@Test
|
||||
public void expireRepositoryDemo() {
|
||||
ExpiringRepositoryDemo<ExpiringSession> demo = new ExpiringRepositoryDemo<>();
|
||||
ExpiringRepositoryDemo<MapSession> demo = new ExpiringRepositoryDemo<>();
|
||||
demo.repository = new MapSessionRepository();
|
||||
|
||||
demo.demo();
|
||||
}
|
||||
|
||||
// tag::expire-repository-demo[]
|
||||
public class ExpiringRepositoryDemo<S extends ExpiringSession> {
|
||||
public class ExpiringRepositoryDemo<S extends Session> {
|
||||
private SessionRepository<S> repository; // <1>
|
||||
|
||||
public void demo() {
|
||||
S toSave = this.repository.createSession(); // <2>
|
||||
// ...
|
||||
toSave.setMaxInactiveIntervalInSeconds(30); // <3>
|
||||
toSave.setMaxInactiveInterval(Duration.ofSeconds(30)); // <3>
|
||||
|
||||
this.repository.save(toSave); // <4>
|
||||
|
||||
S session = this.repository.getSession(toSave.getId()); // <5>
|
||||
S session = this.repository.findById(toSave.getId()); // <5>
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -111,7 +112,7 @@ public class IndexDocTests {
|
||||
public void newRedisOperationsSessionRepository() {
|
||||
// tag::new-redisoperationssessionrepository[]
|
||||
LettuceConnectionFactory factory = new LettuceConnectionFactory();
|
||||
SessionRepository<? extends ExpiringSession> repository = new RedisOperationsSessionRepository(
|
||||
SessionRepository<? extends Session> repository = new RedisOperationsSessionRepository(
|
||||
factory);
|
||||
// end::new-redisoperationssessionrepository[]
|
||||
}
|
||||
@@ -120,7 +121,7 @@ public class IndexDocTests {
|
||||
@SuppressWarnings("unused")
|
||||
public void mapRepository() {
|
||||
// tag::new-mapsessionrepository[]
|
||||
SessionRepository<? extends ExpiringSession> repository = new MapSessionRepository();
|
||||
SessionRepository<? extends Session> repository = new MapSessionRepository();
|
||||
// end::new-mapsessionrepository[]
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ public class IndexDocTests {
|
||||
|
||||
// ... configure transactionManager ...
|
||||
|
||||
SessionRepository<? extends ExpiringSession> repository =
|
||||
SessionRepository<? extends Session> repository =
|
||||
new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
|
||||
// end::new-jdbcoperationssessionrepository[]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2017 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,8 @@
|
||||
|
||||
package docs.http;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -31,11 +33,13 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @author Mark Paluch
|
||||
* @since 1.2
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@@ -63,6 +67,7 @@ public abstract class AbstractHttpSessionListenerTests {
|
||||
RedisConnection connection = mock(RedisConnection.class);
|
||||
|
||||
given(factory.getConnection()).willReturn(connection);
|
||||
given(connection.getConfig(anyString())).willReturn(new Properties());
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package docs.security;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -48,7 +48,7 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
|
||||
@ContextConfiguration(classes = RememberMeSecurityConfiguration.class)
|
||||
@WebAppConfiguration
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class RememberMeSecurityConfigurationTests<T extends ExpiringSession> {
|
||||
public class RememberMeSecurityConfigurationTests<T extends Session> {
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
@@ -81,9 +81,9 @@ public class RememberMeSecurityConfigurationTests<T extends ExpiringSession> {
|
||||
Cookie cookie = result.getResponse().getCookie("SESSION");
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions
|
||||
.getSession(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds())
|
||||
.isEqualTo((int) TimeUnit.DAYS.toSeconds(30));
|
||||
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package docs.security;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -48,7 +48,7 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
|
||||
@ContextConfiguration
|
||||
@WebAppConfiguration
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class RememberMeSecurityConfigurationXmlTests<T extends ExpiringSession> {
|
||||
public class RememberMeSecurityConfigurationXmlTests<T extends Session> {
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
@@ -81,9 +81,9 @@ public class RememberMeSecurityConfigurationXmlTests<T extends ExpiringSession>
|
||||
Cookie cookie = result.getResponse().getCookie("SESSION");
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions
|
||||
.getSession(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds())
|
||||
.isEqualTo((int) TimeUnit.DAYS.toSeconds(30));
|
||||
.findById(new String(Base64.getDecoder().decode(cookie.getValue())));
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(Duration.ofDays(30));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,7 @@ import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private FindByIndexNameSessionRepository<ExpiringSession> sessionRepository;
|
||||
private FindByIndexNameSessionRepository<Session> sessionRepository;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@@ -48,8 +48,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
SpringSessionBackedSessionRegistry sessionRegistry() {
|
||||
return new SpringSessionBackedSessionRegistry<ExpiringSession>(
|
||||
this.sessionRepository);
|
||||
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
springBootVersion=1.5.3.RELEASE
|
||||
version=2.0.0.M1
|
||||
springBootVersion=2.0.0.M2
|
||||
version=2.0.0.M3
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
sonarqube {
|
||||
skipProject = true
|
||||
}
|
||||
@@ -1,177 +1,37 @@
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency 'biz.paluch.redis:lettuce:4.3.1.Final'
|
||||
dependency 'com.maxmind.geoip2:geoip2:2.3.1'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'org.springframework.shell:spring-shell:1.1.0.RELEASE'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
dependency 'org.webjars:html5shiv:3.7.3'
|
||||
dependency 'org.webjars:knockout:2.3.0'
|
||||
dependency 'org.webjars:sockjs-client:0.3.4'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.0'
|
||||
dependency 'org.webjars:webjars-taglib:0.3'
|
||||
}
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-M3'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.0.0.M1'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.0.0.RC1'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Bismuth-M3'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.0.0.RC3'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-RC1'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.0.0.M3'
|
||||
}
|
||||
dependencies {
|
||||
dependency 'antlr:antlr:2.7.7'
|
||||
dependency 'aopalliance:aopalliance:1.0'
|
||||
dependency 'biz.paluch.redis:lettuce:4.3.1.Final'
|
||||
dependency 'cglib:cglib-nodep:2.1_3'
|
||||
dependency 'cglib:cglib-nodep:3.2.4'
|
||||
dependency 'ch.qos.logback:logback-classic:1.1.11'
|
||||
dependency 'ch.qos.logback:logback-classic:1.2.3'
|
||||
dependency 'ch.qos.logback:logback-core:1.1.11'
|
||||
dependency 'ch.qos.logback:logback-core:1.2.3'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-annotations:2.8.0'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-annotations:2.9.0.pr3'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-core:2.8.8'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-core:2.9.0.pr3'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-databind:2.8.8'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.0.pr3'
|
||||
dependency 'com.fasterxml:classmate:1.3.3'
|
||||
dependency 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
dependency 'com.google.code.gson:gson:2.8.0'
|
||||
dependency 'com.google.guava:guava:20.0'
|
||||
dependency 'com.google.http-client:google-http-client:1.20.0'
|
||||
dependency 'com.h2database:h2:1.4.195'
|
||||
dependency 'com.hazelcast:hazelcast-client:3.8'
|
||||
dependency 'com.hazelcast:hazelcast:3.8'
|
||||
dependency 'com.jayway.jsonpath:json-path:2.2.0'
|
||||
dependency 'com.maxmind.db:maxmind-db:1.0.0'
|
||||
dependency 'com.maxmind.geoip2:geoip2:2.3.1'
|
||||
dependency 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1'
|
||||
dependency 'commons-cli:commons-cli:1.3.1'
|
||||
dependency 'commons-codec:commons-codec:1.10'
|
||||
dependency 'commons-collections:commons-collections:3.2.2'
|
||||
dependency 'commons-io:commons-io:2.5'
|
||||
dependency 'dom4j:dom4j:1.6.1'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.0.0.M2'
|
||||
dependency 'io.netty:netty-buffer:4.1.10.Final'
|
||||
dependency 'io.netty:netty-codec:4.1.10.Final'
|
||||
dependency 'io.netty:netty-common:4.1.10.Final'
|
||||
dependency 'io.netty:netty-handler:4.1.10.Final'
|
||||
dependency 'io.netty:netty-resolver:4.1.10.Final'
|
||||
dependency 'io.netty:netty-transport:4.1.10.Final'
|
||||
dependency 'io.projectreactor:reactor-core:3.1.0.M1'
|
||||
dependency 'io.reactivex:rxjava:1.3.0'
|
||||
dependency 'io.lettuce:lettuce-core:5.0.0.RC1'
|
||||
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1'
|
||||
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02'
|
||||
dependency 'javax.servlet:javax.servlet-api:3.1.0'
|
||||
dependency 'javax.transaction:javax.transaction-api:1.2'
|
||||
dependency 'javax.validation:validation-api:1.1.0.Final'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'net.bytebuddy:byte-buddy-agent:1.6.11'
|
||||
dependency 'net.bytebuddy:byte-buddy:1.6.12'
|
||||
dependency 'net.java.dev.jna:jna-platform:4.1.0'
|
||||
dependency 'net.java.dev.jna:jna:4.2.2'
|
||||
dependency 'net.minidev:accessors-smart:1.1'
|
||||
dependency 'net.minidev:json-smart:2.2.1'
|
||||
dependency 'net.sourceforge.cssparser:cssparser:0.9.18'
|
||||
dependency 'net.sourceforge.cssparser:cssparser:0.9.22'
|
||||
dependency 'net.sourceforge.htmlunit:htmlunit-core-js:2.17'
|
||||
dependency 'net.sourceforge.htmlunit:htmlunit-core-js:2.26'
|
||||
dependency 'net.sourceforge.htmlunit:htmlunit:2.21'
|
||||
dependency 'net.sourceforge.htmlunit:htmlunit:2.26'
|
||||
dependency 'net.sourceforge.htmlunit:neko-htmlunit:2.21'
|
||||
dependency 'net.sourceforge.htmlunit:neko-htmlunit:2.25'
|
||||
dependency 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:1.4.0'
|
||||
dependency 'ognl:ognl:3.0.8'
|
||||
dependency 'org.akhikhl.gretty:gretty-runner-tomcat8:1.4.2'
|
||||
dependency 'org.akhikhl.gretty:gretty-runner-tomcat:1.4.2'
|
||||
dependency 'org.akhikhl.gretty:gretty-runner:1.4.2'
|
||||
dependency 'org.apache.commons:commons-compress:1.9'
|
||||
dependency 'org.apache.commons:commons-exec:1.3'
|
||||
dependency 'org.apache.commons:commons-lang3:3.5'
|
||||
dependency 'org.apache.commons:commons-pool2:2.4.2'
|
||||
dependency 'org.apache.derby:derby:10.13.1.1'
|
||||
dependency 'org.apache.httpcomponents:httpclient:4.5.3'
|
||||
dependency 'org.apache.httpcomponents:httpcore:4.4.6'
|
||||
dependency 'org.apache.httpcomponents:httpmime:4.5.3'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-impl:1.2.5'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-spec:1.2.5'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-core:8.5.14'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-el:8.5.14'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-jasper:8.5.14'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.0.33'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.14'
|
||||
dependency 'org.apache.tomcat:tomcat-jdbc:8.5.14'
|
||||
dependency 'org.apache.tomcat:tomcat-juli:8.5.14'
|
||||
dependency 'org.aspectj:aspectjweaver:1.8.10'
|
||||
dependency 'org.assertj:assertj-core:3.6.2'
|
||||
dependency 'org.codehaus.groovy:groovy-json:2.4.11'
|
||||
dependency 'org.codehaus.groovy:groovy:2.4.10'
|
||||
dependency 'org.codehaus.groovy:groovy:2.4.11'
|
||||
dependency 'org.eclipse.jdt.core.compiler:ecj:4.6.1'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.5.v20170502'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.5.v20170502'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-common:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-common:9.4.5.v20170502'
|
||||
dependency 'org.eclipse.jetty:jetty-client:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-client:9.4.5.v20170502'
|
||||
dependency 'org.eclipse.jetty:jetty-http:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-http:9.4.5.v20170502'
|
||||
dependency 'org.eclipse.jetty:jetty-io:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-io:9.4.5.v20170502'
|
||||
dependency 'org.eclipse.jetty:jetty-util:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-util:9.4.5.v20170502'
|
||||
dependency 'org.hamcrest:hamcrest-core:1.3'
|
||||
dependency 'org.hamcrest:hamcrest-library:1.3'
|
||||
dependency 'org.hibernate.common:hibernate-commons-annotations:5.0.1.Final'
|
||||
dependency 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
|
||||
dependency 'org.hibernate:hibernate-core:5.0.12.Final'
|
||||
dependency 'org.hibernate:hibernate-entitymanager:5.0.12.Final'
|
||||
dependency 'org.hibernate:hibernate-validator:5.3.5.Final'
|
||||
dependency 'org.hsqldb:hsqldb:2.4.0'
|
||||
dependency 'org.javassist:javassist:3.21.0-GA'
|
||||
dependency 'org.jboss.logging:jboss-logging:3.3.1.Final'
|
||||
dependency 'org.jboss:jandex:2.0.0.Final'
|
||||
dependency 'org.mockito:mockito-core:2.7.22'
|
||||
dependency 'org.objenesis:objenesis:2.5.1'
|
||||
dependency 'org.ow2.asm:asm:5.0.3'
|
||||
dependency 'org.reactivestreams:reactive-streams:1.0.0'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.21'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.26'
|
||||
dependency 'org.seleniumhq.selenium:selenium-api:2.53.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-api:3.3.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-remote-driver:2.53.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-remote-driver:3.3.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-support:2.53.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-support:3.3.1'
|
||||
dependency 'org.skyscreamer:jsonassert:1.4.0'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:jul-to-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:slf4j-api:1.7.25'
|
||||
dependency 'org.thymeleaf:thymeleaf-spring4:2.1.5.RELEASE'
|
||||
dependency 'org.thymeleaf:thymeleaf:2.1.5.RELEASE'
|
||||
dependency 'org.unbescape:unbescape:1.1.0.RELEASE'
|
||||
dependency 'org.w3c.css:sac:1.3'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
dependency 'org.webjars:html5shiv:3.7.3'
|
||||
dependency 'org.webjars:jquery:1.9.0'
|
||||
dependency 'org.webjars:knockout:2.3.0'
|
||||
dependency 'org.webjars:sockjs-client:0.3.4'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.0'
|
||||
dependency 'org.webjars:webjars-locator-core:0.30'
|
||||
dependency 'org.webjars:webjars-locator-core:0.32'
|
||||
dependency 'org.webjars:webjars-locator:0.32-1'
|
||||
dependency 'org.webjars:webjars-taglib:0.3'
|
||||
dependency 'org.yaml:snakeyaml:1.17'
|
||||
dependency 'redis.clients:jedis:2.9.0'
|
||||
dependency 'xalan:serializer:2.7.2'
|
||||
dependency 'xalan:xalan:2.7.2'
|
||||
dependency 'xerces:xercesImpl:2.11.0'
|
||||
dependency 'xml-apis:xml-apis:1.4.01'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import org.gradle.plugins.ide.eclipse.model.ProjectDependency
|
||||
import org.gradle.plugins.ide.eclipse.model.SourceFolder
|
||||
|
||||
|
||||
apply plugin: "propdeps-eclipse"
|
||||
apply plugin: "propdeps-idea"
|
||||
|
||||
eclipse {
|
||||
jdt {
|
||||
javaRuntimeName = "J2SE-1.5"
|
||||
}
|
||||
}
|
||||
|
||||
eclipse.project.buildCommand "net.sf.eclipsecs.core.CheckstyleBuilder"
|
||||
eclipse.project.natures "net.sf.eclipsecs.core.CheckstyleNature"
|
||||
|
||||
// Include project specific settings
|
||||
task eclipseCheckstyle(type: Copy) {
|
||||
from rootProject.files(
|
||||
"eclipse/.checkstyle")
|
||||
into project.projectDir
|
||||
expand(configDir: rootProject.file('config/checkstyle').absolutePath)
|
||||
}
|
||||
|
||||
task eclipseSettings(type: Copy) {
|
||||
from rootProject.files(
|
||||
"eclipse/org.eclipse.jdt.ui.prefs",
|
||||
"eclipse/org.eclipse.wst.common.project.facet.core.xml")
|
||||
into project.file('.settings/')
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
task eclipseWstComponent(type: Copy) {
|
||||
from rootProject.files(
|
||||
"eclipse/org.eclipse.wst.common.component")
|
||||
into project.file('.settings/')
|
||||
expand(deployname: project.name)
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
task eclipseJdtPrepare(type: Copy) {
|
||||
from rootProject.file("eclipse/org.eclipse.jdt.core.prefs")
|
||||
into project.file(".settings/")
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
task cleanEclipseJdtUi(type: Delete) {
|
||||
delete project.file(".settings/org.eclipse.jdt.core.prefs")
|
||||
delete project.file(".settings/org.eclipse.jdt.ui.prefs")
|
||||
delete project.file(".settings/org.eclipse.wst.common.component")
|
||||
delete project.file(".settings/org.eclipse.wst.common.project.facet.core.xml")
|
||||
}
|
||||
|
||||
task eclipseConfiguration(dependsOn: [eclipseCheckstyle, eclipseJdtPrepare, eclipseSettings, eclipseWstComponent]) {
|
||||
group 'ide'
|
||||
}
|
||||
|
||||
tasks["eclipseJdt"].dependsOn(eclipseJdtPrepare)
|
||||
tasks["cleanEclipse"].dependsOn(cleanEclipseJdtUi)
|
||||
tasks["eclipse"].dependsOn(eclipseConfiguration)
|
||||
@@ -1,92 +0,0 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'javadocHotfix'
|
||||
apply plugin: 'eclipse-wtp'
|
||||
apply plugin: 'propdeps'
|
||||
apply plugin: 'propdeps-idea'
|
||||
apply plugin: 'propdeps-eclipse'
|
||||
apply plugin: 'com.github.ben-manes.versions'
|
||||
apply plugin: 'checkstyle'
|
||||
apply from: IDE_GRADLE
|
||||
|
||||
group = 'org.springframework.session'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'Cairo-BUILD-SNAPSHOT'
|
||||
|
||||
ext.seleniumDependencies = [
|
||||
"org.seleniumhq.selenium:htmlunit-driver:$htmlUnitVersion",
|
||||
"org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
|
||||
]
|
||||
|
||||
ext.jstlDependencies = [
|
||||
"javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:$jstlVersion",
|
||||
"org.apache.taglibs:taglibs-standard-jstlel:1.2.1"
|
||||
]
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://repo.spring.io/libs-snapshot' }
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
||||
if (details.requested.group == 'org.springframework') {
|
||||
details.useVersion springVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
// Integration test setup
|
||||
configurations {
|
||||
integrationTestCompile {
|
||||
extendsFrom testCompile, optional, provided
|
||||
}
|
||||
integrationTestRuntime {
|
||||
extendsFrom integrationTestCompile, testRuntime
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
integrationTest {
|
||||
java.srcDir file('src/integration-test/java')
|
||||
groovy.srcDirs file('src/integration-test/groovy')
|
||||
resources.srcDir file('src/integration-test/resources')
|
||||
compileClasspath = sourceSets.main.output + sourceSets.test.output + configurations.integrationTestCompile
|
||||
runtimeClasspath = output + compileClasspath + configurations.integrationTestRuntime
|
||||
}
|
||||
}
|
||||
|
||||
task integrationTest(type: Test, dependsOn: jar) {
|
||||
testClassesDir = sourceSets.integrationTest.output.classesDir
|
||||
logging.captureStandardOutput(LogLevel.INFO)
|
||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||
maxParallelForks = 1
|
||||
reports {
|
||||
html.destination = project.file("$project.buildDir/reports/integration-tests/")
|
||||
junitXml.destination = project.file("$project.buildDir/integration-test-results/")
|
||||
}
|
||||
}
|
||||
check.dependsOn integrationTest
|
||||
|
||||
checkstyle {
|
||||
configFile = rootProject.file('config/checkstyle/checkstyle.xml')
|
||||
configProperties.configDir = configFile.parentFile
|
||||
toolVersion = '6.16.1'
|
||||
}
|
||||
|
||||
task checkstyle {
|
||||
dependsOn project.tasks.findAll { task -> task.name.matches('checkstyle\\w+') }
|
||||
}
|
||||
|
||||
eclipse {
|
||||
classpath {
|
||||
plusConfigurations += [ configurations.integrationTestCompile ]
|
||||
}
|
||||
}
|
||||
|
||||
project.idea.module {
|
||||
scopes.TEST.plus += [project.configurations.integrationTestRuntime]
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
apply plugin: 'propdeps-maven'
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
customizePom(pom, project)
|
||||
}
|
||||
}
|
||||
|
||||
def customizePom(pom, gradleProject) {
|
||||
pom.whenConfigured { generatedPom ->
|
||||
|
||||
// sort to make pom dependencies order consistent to ease comparison of older poms
|
||||
generatedPom.dependencies = generatedPom.dependencies.sort { dep ->
|
||||
"$dep.scope:$dep.groupId:$dep.artifactId"
|
||||
}
|
||||
|
||||
// add all items necessary for maven central publication
|
||||
generatedPom.project {
|
||||
name = gradleProject.description
|
||||
description = gradleProject.description
|
||||
url = "https://github.com/spring-projects/spring-session"
|
||||
organization {
|
||||
name = "Spring IO"
|
||||
url = "http://projects.spring.io/spring-session"
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = "https://github.com/spring-projects/spring-session"
|
||||
connection = "scm:git:git://github.com/spring-projects/spring-session"
|
||||
developerConnection = "scm:git:git://github.com/spring-projects/spring-session"
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = "rwinch"
|
||||
name = "Rob Winch"
|
||||
email = "rwinch@pivotal.io"
|
||||
}
|
||||
}
|
||||
issueManagement {
|
||||
system = "GitHub"
|
||||
url = "https://github.com/spring-projects/spring-session/issues"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
sonarqube {
|
||||
skipProject = true
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
configurations {
|
||||
spring3TestRuntime.extendsFrom testRuntime
|
||||
}
|
||||
|
||||
configurations.spring3TestRuntime {
|
||||
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
||||
if (details.requested.group == 'org.springframework'
|
||||
&& details.requested.name != 'spring-websocket'
|
||||
&& details.requested.name != 'spring-messaging') {
|
||||
details.useVersion '3.2.18.RELEASE'
|
||||
}
|
||||
if (details.requested.group == 'org.springframework.data') {
|
||||
if (details.requested.name == 'spring-data-commons') {
|
||||
details.useVersion '1.12.1.RELEASE'
|
||||
}
|
||||
if (details.requested.name == 'spring-data-keyvalue') {
|
||||
details.useVersion '1.1.1.RELEASE'
|
||||
}
|
||||
if (details.requested.name == 'spring-data-redis') {
|
||||
details.useVersion '1.7.1.RELEASE'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task spring3Test(type: Test) {
|
||||
jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=128M']
|
||||
classpath = sourceSets.test.output + sourceSets.main.output + configurations.spring3TestRuntime
|
||||
exclude "org/springframework/session/web/socket/**"
|
||||
reports {
|
||||
html.destination = project.file("$buildDir/spring3-test-results/")
|
||||
junitXml.destination = project.file("$buildDir/reports/spring3-tests/")
|
||||
}
|
||||
}
|
||||
|
||||
//check.dependsOn spring3Test
|
||||
@@ -1,61 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://repo.spring.io/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.bmuschko:gradle-tomcat-plugin:2.2.5")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'war'
|
||||
apply plugin: 'com.bmuschko.tomcat'
|
||||
|
||||
[tomcatRun,tomcatRunWar]*.contextPath = '/'
|
||||
|
||||
|
||||
task integrationTomcatRun(type: com.bmuschko.gradle.tomcat.tasks.TomcatRun) {
|
||||
onlyIf { !sourceSets.integrationTest.allSource.empty }
|
||||
contextPath = tomcatRun.contextPath
|
||||
daemon = true
|
||||
tomcatClasspath = tomcatRun.tomcatClasspath
|
||||
webAppClasspath = tomcatRun.webAppClasspath
|
||||
webAppSourceDirectory = tomcatRun.webAppSourceDirectory
|
||||
doFirst {
|
||||
def mainOutputDir = project.sourceSets.main.output.classesDir
|
||||
if(mainOutputDir) {
|
||||
classesDirectory = mainOutputDir
|
||||
}
|
||||
// delay reserving ports to ensure they are still available
|
||||
def ports = reservePorts(3)
|
||||
httpPort = ports[0]
|
||||
ajpPort = ports[1]
|
||||
stopPort = ports[2]
|
||||
|
||||
System.setProperty('spring.session.redis.namespace',project.name)
|
||||
}
|
||||
}
|
||||
|
||||
task integrationTomcatStop(type: com.bmuschko.gradle.tomcat.tasks.TomcatStop) {
|
||||
onlyIf { !sourceSets.integrationTest.allSource.empty }
|
||||
doFirst {
|
||||
stopPort = integrationTomcatRun.stopPort
|
||||
}
|
||||
}
|
||||
|
||||
integrationTest {
|
||||
dependsOn integrationTomcatRun
|
||||
doFirst {
|
||||
systemProperties['tomcat.port'] = integrationTomcatRun.httpPort
|
||||
}
|
||||
finalizedBy integrationTomcatStop
|
||||
}
|
||||
|
||||
def reservePorts(int count) {
|
||||
def sockets = []
|
||||
for(int i in 1..count) {
|
||||
sockets << new ServerSocket(0)
|
||||
}
|
||||
def result = sockets*.localPort
|
||||
sockets*.close()
|
||||
result
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
apply from: TOMCAT_GRADLE
|
||||
|
||||
dependencies {
|
||||
def tomcatVersion = '6.0.43'
|
||||
tomcat "org.apache.tomcat:catalina:${tomcatVersion}",
|
||||
"org.apache.tomcat:coyote:${tomcatVersion}",
|
||||
"org.apache.tomcat:jasper:${tomcatVersion}"
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
apply from: TOMCAT_GRADLE
|
||||
|
||||
dependencies {
|
||||
def tomcatVersion = '7.0.59'
|
||||
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
|
||||
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
|
||||
"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
|
||||
}
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Wed Jan 11 10:54:44 CST 2017
|
||||
#Fri Jul 07 11:11:13 CDT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
|
||||
|
||||
19
gradlew
vendored
19
gradlew
vendored
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -154,16 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save ( ) {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis"
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-security"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile "org.springframework.session:spring-session"
|
||||
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
|
||||
compile "org.webjars:bootstrap"
|
||||
compile "org.webjars:html5shiv"
|
||||
|
||||
@@ -18,10 +18,10 @@ package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig extends WebMvcConfigurerAdapter {
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Secured Content</title>
|
||||
</head>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorator="layout">
|
||||
layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Log In</title>
|
||||
</head>
|
||||
@@ -44,4 +44,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,152 +1,6 @@
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency 'antlr:antlr:2.7.7'
|
||||
dependency 'aopalliance:aopalliance:1.0'
|
||||
dependency 'biz.paluch.redis:lettuce:4.3.1.Final'
|
||||
dependency 'cglib:cglib-nodep:2.1_3'
|
||||
dependency 'ch.qos.logback:logback-classic:1.1.11'
|
||||
dependency 'ch.qos.logback:logback-core:1.1.11'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-annotations:2.8.0'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-core:2.8.8'
|
||||
dependency 'com.fasterxml.jackson.core:jackson-databind:2.8.8'
|
||||
dependency 'com.fasterxml:classmate:1.3.3'
|
||||
dependency 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
dependency 'com.google.code.gson:gson:2.8.0'
|
||||
dependency 'com.google.guava:guava:20.0'
|
||||
dependency 'com.google.http-client:google-http-client:1.20.0'
|
||||
dependency 'com.h2database:h2:1.4.194'
|
||||
dependency 'com.jayway.jsonpath:json-path:2.2.0'
|
||||
dependency 'com.maxmind.db:maxmind-db:1.0.0'
|
||||
dependency 'com.maxmind.geoip2:geoip2:2.3.1'
|
||||
dependency 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1'
|
||||
dependency 'commons-codec:commons-codec:1.10'
|
||||
dependency 'commons-collections:commons-collections:3.2.2'
|
||||
dependency 'commons-io:commons-io:2.5'
|
||||
dependency 'dom4j:dom4j:1.6.1'
|
||||
dependency 'io.netty:netty-buffer:4.1.10.Final'
|
||||
dependency 'io.netty:netty-codec:4.1.10.Final'
|
||||
dependency 'io.netty:netty-common:4.1.10.Final'
|
||||
dependency 'io.netty:netty-handler:4.1.10.Final'
|
||||
dependency 'io.netty:netty-resolver:4.1.10.Final'
|
||||
dependency 'io.netty:netty-transport:4.1.10.Final'
|
||||
dependency 'io.reactivex:rxjava:1.3.0'
|
||||
dependency 'javax.transaction:javax.transaction-api:1.2'
|
||||
dependency 'javax.validation:validation-api:1.1.0.Final'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'net.java.dev.jna:jna-platform:4.1.0'
|
||||
dependency 'net.java.dev.jna:jna:4.2.2'
|
||||
dependency 'net.minidev:accessors-smart:1.1'
|
||||
dependency 'net.minidev:json-smart:2.2.1'
|
||||
dependency 'net.sourceforge.cssparser:cssparser:0.9.18'
|
||||
dependency 'net.sourceforge.htmlunit:htmlunit-core-js:2.17'
|
||||
dependency 'net.sourceforge.htmlunit:htmlunit:2.21'
|
||||
dependency 'net.sourceforge.htmlunit:neko-htmlunit:2.21'
|
||||
dependency 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:1.4.0'
|
||||
dependency 'ognl:ognl:3.0.8'
|
||||
dependency 'org.apache.commons:commons-compress:1.9'
|
||||
dependency 'org.apache.commons:commons-exec:1.3'
|
||||
dependency 'org.apache.commons:commons-lang3:3.5'
|
||||
dependency 'org.apache.commons:commons-pool2:2.4.2'
|
||||
dependency 'org.apache.httpcomponents:httpclient:4.5.3'
|
||||
dependency 'org.apache.httpcomponents:httpcore:4.4.6'
|
||||
dependency 'org.apache.httpcomponents:httpmime:4.5.3'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-core:8.5.14'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-el:8.5.14'
|
||||
dependency 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.14'
|
||||
dependency 'org.apache.tomcat:tomcat-jdbc:8.5.14'
|
||||
dependency 'org.apache.tomcat:tomcat-juli:8.5.14'
|
||||
dependency 'org.aspectj:aspectjweaver:1.8.10'
|
||||
dependency 'org.assertj:assertj-core:2.6.0'
|
||||
dependency 'org.codehaus.groovy:groovy:2.4.10'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty.websocket:websocket-common:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-client:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-http:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-io:9.4.4.v20170414'
|
||||
dependency 'org.eclipse.jetty:jetty-util:9.4.4.v20170414'
|
||||
dependency 'org.hamcrest:hamcrest-core:1.3'
|
||||
dependency 'org.hamcrest:hamcrest-library:1.3'
|
||||
dependency 'org.hibernate.common:hibernate-commons-annotations:5.0.1.Final'
|
||||
dependency 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
|
||||
dependency 'org.hibernate:hibernate-core:5.0.12.Final'
|
||||
dependency 'org.hibernate:hibernate-entitymanager:5.0.12.Final'
|
||||
dependency 'org.hibernate:hibernate-validator:5.3.5.Final'
|
||||
dependency 'org.javassist:javassist:3.21.0-GA'
|
||||
dependency 'org.jboss.logging:jboss-logging:3.3.1.Final'
|
||||
dependency 'org.jboss:jandex:2.0.0.Final'
|
||||
dependency 'org.mockito:mockito-core:1.10.19'
|
||||
dependency 'org.objenesis:objenesis:2.5.1'
|
||||
dependency 'org.ow2.asm:asm:5.0.3'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.21'
|
||||
dependency 'org.seleniumhq.selenium:selenium-api:2.53.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-remote-driver:2.53.1'
|
||||
dependency 'org.seleniumhq.selenium:selenium-support:2.53.1'
|
||||
dependency 'org.skyscreamer:jsonassert:1.4.0'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:jul-to-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:slf4j-api:1.7.25'
|
||||
dependency 'org.springframework.boot:spring-boot-autoconfigure:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-aop:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-data-jpa:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-jdbc:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-logging:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-security:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-test:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-thymeleaf:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-tomcat:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-web:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter-websocket:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-starter:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-test-autoconfigure:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot-test:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.boot:spring-boot:1.5.3.RELEASE'
|
||||
dependency 'org.springframework.data:spring-data-commons:1.13.3.RELEASE'
|
||||
dependency 'org.springframework.data:spring-data-jpa:1.11.3.RELEASE'
|
||||
dependency 'org.springframework.data:spring-data-keyvalue:1.2.3.RELEASE'
|
||||
dependency 'org.springframework.data:spring-data-redis:1.8.3.RELEASE'
|
||||
dependency 'org.springframework.security:spring-security-config:4.2.2.RELEASE'
|
||||
dependency 'org.springframework.security:spring-security-core:4.2.2.RELEASE'
|
||||
dependency 'org.springframework.security:spring-security-data:4.2.2.RELEASE'
|
||||
dependency 'org.springframework.security:spring-security-messaging:4.2.2.RELEASE'
|
||||
dependency 'org.springframework.security:spring-security-test:4.2.2.RELEASE'
|
||||
dependency 'org.springframework.security:spring-security-web:4.2.2.RELEASE'
|
||||
dependency 'org.springframework:spring-aop:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-aspects:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-beans:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-context-support:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-context:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-core:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-expression:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-jcl:5.0.0.RC1'
|
||||
dependency 'org.springframework:spring-jdbc:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-messaging:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-orm:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-oxm:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-test:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-tx:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-web:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-webmvc:4.3.8.RELEASE'
|
||||
dependency 'org.springframework:spring-websocket:4.3.8.RELEASE'
|
||||
dependency 'org.thymeleaf:thymeleaf-spring4:2.1.5.RELEASE'
|
||||
dependency 'org.thymeleaf:thymeleaf:2.1.5.RELEASE'
|
||||
dependency 'org.unbescape:unbescape:1.1.0.RELEASE'
|
||||
dependency 'org.w3c.css:sac:1.3'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
dependency 'org.webjars:html5shiv:3.7.3'
|
||||
dependency 'org.webjars:jquery:1.9.0'
|
||||
dependency 'org.webjars:knockout:2.3.0'
|
||||
dependency 'org.webjars:sockjs-client:0.3.4'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.0'
|
||||
dependency 'org.webjars:webjars-locator-core:0.32'
|
||||
dependency 'org.webjars:webjars-locator:0.32-1'
|
||||
dependency 'org.yaml:snakeyaml:1.17'
|
||||
dependency 'redis.clients:jedis:2.9.0'
|
||||
dependency 'xalan:serializer:2.7.2'
|
||||
dependency 'xalan:xalan:2.7.2'
|
||||
dependency 'xerces:xercesImpl:2.11.0'
|
||||
dependency 'xml-apis:xml-apis:1.4.01'
|
||||
}
|
||||
dependencies {
|
||||
dependency 'io.lettuce:lettuce-core:5.0.0.M2'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-jdbc')
|
||||
compile "org.springframework.boot:spring-boot-starter-jdbc"
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-security"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile "org.springframework.session:spring-session"
|
||||
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
|
||||
compile "org.webjars:bootstrap"
|
||||
compile "org.webjars:html5shiv"
|
||||
|
||||
@@ -18,10 +18,10 @@ package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig extends WebMvcConfigurerAdapter {
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Secured Content</title>
|
||||
</head>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
exclude module: 'commons-pool2'
|
||||
}
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis"
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-security"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile "org.springframework.session:spring-session"
|
||||
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
|
||||
compile "org.webjars:bootstrap"
|
||||
compile "org.webjars:html5shiv"
|
||||
compile "org.webjars:webjars-locator"
|
||||
compile "biz.paluch.redis:lettuce"
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "org.apache.httpcomponents:httpclient"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
@@ -38,11 +37,6 @@ public class SessionConfig implements BeanClassLoaderAware {
|
||||
return new GenericJackson2JsonRedisSerializer(objectMapper());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LettuceConnectionFactory connectionFactory() {
|
||||
return new LettuceConnectionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customized {@link ObjectMapper} to add mix-in for class that doesn't have default
|
||||
* constructors
|
||||
|
||||
@@ -18,10 +18,10 @@ package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig extends WebMvcConfigurerAdapter {
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Home</title>
|
||||
</head>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis"
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-security"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile "org.springframework.session:spring-session"
|
||||
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
|
||||
compile "org.webjars:bootstrap"
|
||||
compile "org.webjars:html5shiv"
|
||||
|
||||
@@ -18,10 +18,10 @@ package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig extends WebMvcConfigurerAdapter {
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>Secured Content</title>
|
||||
</head>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
exclude module: 'commons-pool2'
|
||||
}
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis"
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-security"
|
||||
compile "org.springframework.boot:spring-boot-starter-data-jpa"
|
||||
compile "org.springframework.boot:spring-boot-starter-websocket"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile "org.springframework.session:spring-session"
|
||||
compile "org.springframework:spring-websocket"
|
||||
compile "org.springframework.security:spring-security-messaging"
|
||||
compile "org.springframework.security:spring-security-data"
|
||||
@@ -20,7 +19,7 @@ dependencies {
|
||||
compile "org.webjars:sockjs-client"
|
||||
compile "org.webjars:stomp-websocket"
|
||||
compile "org.webjars:webjars-locator"
|
||||
compile "biz.paluch.redis:lettuce"
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "com.h2database:h2"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
@@ -18,10 +18,10 @@ package sample.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfig extends WebMvcConfigurerAdapter {
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package sample.websocket;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import sample.data.ActiveWebSocketUser;
|
||||
import sample.data.ActiveWebSocketUserRepository;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
@@ -42,14 +41,10 @@ public class WebSocketDisconnectHandler<S>
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
ActiveWebSocketUser user = this.repository.findOne(id);
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.repository.delete(id);
|
||||
this.messagingTemplate.convertAndSend("/topic/friends/signout",
|
||||
Arrays.asList(user.getUsername()));
|
||||
|
||||
this.repository.findById(id).ifPresent(user -> {
|
||||
this.repository.deleteById(id);
|
||||
this.messagingTemplate.convertAndSend("/topic/friends/signout",
|
||||
Arrays.asList(user.getUsername()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>View All</title>
|
||||
</head>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
}
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework:spring-web"
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "org.webjars:bootstrap"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session')
|
||||
compile project(':spring-session-hazelcast')
|
||||
compile "org.springframework:spring-web"
|
||||
compile "org.springframework.security:spring-security-config"
|
||||
compile "org.springframework.security:spring-security-web"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
}
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework:spring-web"
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "org.webjars:bootstrap"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
}
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "org.springframework:spring-webmvc"
|
||||
compile "org.springframework.security:spring-security-config"
|
||||
@@ -19,4 +17,4 @@ dependencies {
|
||||
testCompile "org.assertj:assertj-core"
|
||||
testCompile "org.springframework:spring-test"
|
||||
testCompile "commons-codec:commons-codec"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import sample.mvc.MvcConfig;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@@ -50,7 +50,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
public class RestMockMvcTests {
|
||||
|
||||
@Autowired
|
||||
SessionRepositoryFilter<? extends ExpiringSession> sessionRepositoryFilter;
|
||||
SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
|
||||
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
}
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework:spring-web"
|
||||
compile "org.springframework.security:spring-security-config"
|
||||
compile "org.springframework.security:spring-security-web"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
}
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework:spring-web"
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "org.webjars:bootstrap"
|
||||
|
||||
@@ -61,7 +61,7 @@ public class UserAccountsFilter implements Filter {
|
||||
String alias = entry.getKey();
|
||||
String sessionId = entry.getValue();
|
||||
|
||||
Session session = repo.getSession(sessionId);
|
||||
Session session = repo.findById(sessionId);
|
||||
if (session == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session')
|
||||
compile project(':spring-session-core')
|
||||
compile "org.webjars:bootstrap"
|
||||
compile "org.webjars:webjars-taglib"
|
||||
compile "com.hazelcast:hazelcast-client"
|
||||
|
||||
@@ -23,52 +23,35 @@ import java.util.Map;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.FilterRegistration.Dynamic;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import javax.servlet.annotation.WebListener;
|
||||
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.config.MapConfig;
|
||||
import com.hazelcast.config.NetworkConfig;
|
||||
import com.hazelcast.config.SerializerConfig;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
|
||||
@WebListener
|
||||
public class Initializer implements ServletContextListener {
|
||||
|
||||
private static final String SESSION_MAP_NAME = "spring:session:sessions";
|
||||
|
||||
private HazelcastInstance instance;
|
||||
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
String sessionMapName = "spring:session:sessions";
|
||||
ServletContext sc = sce.getServletContext();
|
||||
this.instance = createHazelcastInstance();
|
||||
Map<String, Session> sessions = this.instance.getMap(SESSION_MAP_NAME);
|
||||
|
||||
Config cfg = new Config();
|
||||
NetworkConfig netConfig = new NetworkConfig();
|
||||
netConfig.setPort(getAvailablePort());
|
||||
cfg.setNetworkConfig(netConfig);
|
||||
SerializerConfig serializer = new SerializerConfig().setTypeClass(Object.class)
|
||||
.setImplementation(new ObjectStreamSerializer());
|
||||
cfg.getSerializationConfig().addSerializerConfig(serializer);
|
||||
MapConfig mc = new MapConfig();
|
||||
mc.setName(sessionMapName);
|
||||
mc.setTimeToLiveSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
cfg.addMapConfig(mc);
|
||||
|
||||
this.instance = Hazelcast.newHazelcastInstance(cfg);
|
||||
Map<String, ExpiringSession> sessions = this.instance.getMap(sessionMapName);
|
||||
|
||||
SessionRepository<ExpiringSession> sessionRepository = new MapSessionRepository(
|
||||
sessions);
|
||||
SessionRepositoryFilter<ExpiringSession> filter = new SessionRepositoryFilter<>(
|
||||
MapSessionRepository sessionRepository = new MapSessionRepository(sessions);
|
||||
SessionRepositoryFilter<? extends Session> filter = new SessionRepositoryFilter<>(
|
||||
sessionRepository);
|
||||
Dynamic fr = sc.addFilter("springSessionFilter", filter);
|
||||
|
||||
Dynamic fr = sce.getServletContext().addFilter("springSessionFilter", filter);
|
||||
fr.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
|
||||
}
|
||||
|
||||
@@ -76,6 +59,17 @@ public class Initializer implements ServletContextListener {
|
||||
this.instance.shutdown();
|
||||
}
|
||||
|
||||
private HazelcastInstance createHazelcastInstance() {
|
||||
Config config = new Config();
|
||||
|
||||
config.getNetworkConfig().setPort(getAvailablePort());
|
||||
|
||||
config.getMapConfig(SESSION_MAP_NAME)
|
||||
.setTimeToLiveSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
return Hazelcast.newHazelcastInstance(config);
|
||||
}
|
||||
|
||||
private static int getAvailablePort() {
|
||||
ServerSocket socket = null;
|
||||
try {
|
||||
@@ -93,4 +87,5 @@ public class Initializer implements ServletContextListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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 sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.hazelcast.nio.ObjectDataInput;
|
||||
import com.hazelcast.nio.ObjectDataOutput;
|
||||
import com.hazelcast.nio.serialization.StreamSerializer;
|
||||
|
||||
/**
|
||||
* A {@link StreamSerializer} that uses Java serialization to persist the session. This is
|
||||
* certainly not the most efficient way to persist sessions, but the example is intended
|
||||
* to demonstrate using minimal dependencies. For better serialization methods try using
|
||||
* <a href="https://github.com/EsotericSoftware/kryo">Kryo</a>.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class ObjectStreamSerializer implements StreamSerializer<Object> {
|
||||
public int getTypeId() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void write(ObjectDataOutput objectDataOutput, Object object)
|
||||
throws IOException {
|
||||
ObjectOutputStream out = new ObjectOutputStream((OutputStream) objectDataOutput);
|
||||
out.writeObject(object);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public Object read(ObjectDataInput objectDataInput) throws IOException {
|
||||
ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput);
|
||||
try {
|
||||
return in.readObject();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-war'
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
}
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework:spring-web"
|
||||
compile "io.lettuce:lettuce-core"
|
||||
compile "org.webjars:bootstrap"
|
||||
|
||||
@@ -5,25 +5,18 @@ description = "Spring Session"
|
||||
dependencies {
|
||||
compile "org.springframework:spring-jcl"
|
||||
|
||||
optional "io.projectreactor:reactor-core"
|
||||
optional "javax.servlet:javax.servlet-api"
|
||||
optional "org.springframework:spring-context"
|
||||
optional "org.springframework:spring-jdbc"
|
||||
optional "org.springframework:spring-messaging"
|
||||
optional "org.springframework:spring-web"
|
||||
optional "org.springframework:spring-webflux"
|
||||
optional "org.springframework:spring-websocket"
|
||||
optional "org.springframework.data:spring-data-redis"
|
||||
optional "org.springframework.security:spring-security-core"
|
||||
optional "org.springframework.security:spring-security-web"
|
||||
optional "com.hazelcast:hazelcast"
|
||||
|
||||
provided "javax.servlet:javax.servlet-api"
|
||||
|
||||
integrationTestCompile "redis.clients:jedis"
|
||||
integrationTestCompile "org.apache.commons:commons-pool2"
|
||||
integrationTestCompile "org.apache.derby:derby"
|
||||
integrationTestCompile "com.h2database:h2"
|
||||
integrationTestCompile "com.hazelcast:hazelcast-client"
|
||||
integrationTestCompile "org.hsqldb:hsqldb"
|
||||
|
||||
testCompile "io.projectreactor:reactor-test"
|
||||
testCompile "junit:junit"
|
||||
testCompile "org.mockito:mockito-core"
|
||||
testCompile "edu.umd.cs.mtc:multithreadedtc"
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
|
||||
/**
|
||||
* A {@link SessionRepository} backed by a {@link Map} and that uses a
|
||||
* {@link MapSession}. By default a {@link ConcurrentHashMap} is
|
||||
* used, but a custom {@link Map} can be injected to use distributed maps
|
||||
* provided by NoSQL stores like Redis and Hazelcast.
|
||||
*
|
||||
* <p>
|
||||
* The implementation does NOT support firing {@link SessionDeletedEvent} or
|
||||
* {@link SessionExpiredEvent}.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MapReactorSessionRepository implements ReactorSessionRepository<MapSession> {
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
|
||||
private final Map<String, Session> sessions;
|
||||
|
||||
/**
|
||||
* Creates an instance backed by a {@link ConcurrentHashMap}.
|
||||
*/
|
||||
public MapReactorSessionRepository() {
|
||||
this(new ConcurrentHashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link Map}. This allows
|
||||
* injecting a distributed {@link Map}.
|
||||
*
|
||||
* @param sessions the {@link Map} to use. Cannot be null.
|
||||
*/
|
||||
public MapReactorSessionRepository(Map<String, Session> sessions) {
|
||||
if (sessions == null) {
|
||||
throw new IllegalArgumentException("sessions cannot be null");
|
||||
}
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link Map}. This allows
|
||||
* injecting a distributed {@link Map}.
|
||||
*
|
||||
* @param sessions the {@link Map} to use. Cannot be null.
|
||||
*/
|
||||
public MapReactorSessionRepository(Session... sessions) {
|
||||
if (sessions == null) {
|
||||
throw new IllegalArgumentException("sessions cannot be null");
|
||||
}
|
||||
this.sessions = new ConcurrentHashMap<>();
|
||||
for (Session session : sessions) {
|
||||
this.performSave(new MapSession(session));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link Map}. This allows
|
||||
* injecting a distributed {@link Map}.
|
||||
*
|
||||
* @param sessions the {@link Map} to use. Cannot be null.
|
||||
*/
|
||||
public MapReactorSessionRepository(Iterable<Session> sessions) {
|
||||
if (sessions == null) {
|
||||
throw new IllegalArgumentException("sessions cannot be null");
|
||||
}
|
||||
this.sessions = new ConcurrentHashMap<>();
|
||||
for (Session session : sessions) {
|
||||
this.performSave(new MapSession(session));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
|
||||
}
|
||||
|
||||
public Mono<Void> save(MapSession session) {
|
||||
return Mono.fromRunnable(() -> performSave(session));
|
||||
}
|
||||
|
||||
private void performSave(MapSession session) {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
public Mono<MapSession> findById(String id) {
|
||||
return Mono.defer(() -> {
|
||||
Session saved = this.sessions.get(id);
|
||||
if (saved == null) {
|
||||
return Mono.empty();
|
||||
}
|
||||
if (saved.isExpired()) {
|
||||
delete(saved.getId());
|
||||
return Mono.empty();
|
||||
}
|
||||
return Mono.just(new MapSession(saved));
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<Void> delete(String id) {
|
||||
return Mono.fromRunnable(() -> this.sessions.remove(id));
|
||||
}
|
||||
|
||||
public Mono<MapSession> createSession() {
|
||||
return Mono.defer(() -> {
|
||||
MapSession result = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveInterval(
|
||||
Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
return Mono.just(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,12 @@
|
||||
package org.springframework.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -41,31 +42,34 @@ import java.util.concurrent.TimeUnit;
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class MapSession implements ExpiringSession, Serializable {
|
||||
public final class MapSession implements Session, Serializable {
|
||||
/**
|
||||
* Default {@link #setMaxInactiveIntervalInSeconds(int)} (30 minutes).
|
||||
* Default {@link #setMaxInactiveInterval(Duration)} (30 minutes).
|
||||
*/
|
||||
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
|
||||
|
||||
private String id;
|
||||
private String originalId;
|
||||
private Map<String, Object> sessionAttrs = new HashMap<>();
|
||||
private long creationTime = System.currentTimeMillis();
|
||||
private long lastAccessedTime = this.creationTime;
|
||||
private Instant creationTime = Instant.now();
|
||||
private Instant lastAccessedTime = this.creationTime;
|
||||
|
||||
/**
|
||||
* Defaults to 30 minutes.
|
||||
*/
|
||||
private int maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
private Duration maxInactiveInterval = Duration.ofSeconds(DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
|
||||
/**
|
||||
* Creates a new instance with a secure randomly generated identifier.
|
||||
*/
|
||||
public MapSession() {
|
||||
this(UUID.randomUUID().toString());
|
||||
this(generateId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance with the specified id. This is preferred to the default
|
||||
* constructor when the id is known to prevent unnecessary consumption on entropy
|
||||
@@ -75,6 +79,7 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
*/
|
||||
public MapSession(String id) {
|
||||
this.id = id;
|
||||
this.originalId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,27 +88,30 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
* @param session the {@link Session} to initialize this {@link Session} with. Cannot
|
||||
* be null.
|
||||
*/
|
||||
public MapSession(ExpiringSession session) {
|
||||
public MapSession(Session session) {
|
||||
if (session == null) {
|
||||
throw new IllegalArgumentException("session cannot be null");
|
||||
}
|
||||
this.id = session.getId();
|
||||
this.originalId = this.id;
|
||||
this.sessionAttrs = new HashMap<>(
|
||||
session.getAttributeNames().size());
|
||||
for (String attrName : session.getAttributeNames()) {
|
||||
Object attrValue = session.getAttribute(attrName);
|
||||
this.sessionAttrs.put(attrName, attrValue);
|
||||
if (attrValue != null) {
|
||||
this.sessionAttrs.put(attrName, attrValue);
|
||||
}
|
||||
}
|
||||
this.lastAccessedTime = session.getLastAccessedTime();
|
||||
this.creationTime = session.getCreationTime();
|
||||
this.maxInactiveInterval = session.getMaxInactiveIntervalInSeconds();
|
||||
this.maxInactiveInterval = session.getMaxInactiveInterval();
|
||||
}
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
public void setLastAccessedTime(Instant lastAccessedTime) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
public Instant getCreationTime() {
|
||||
return this.creationTime;
|
||||
}
|
||||
|
||||
@@ -111,28 +119,41 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
String getOriginalId() {
|
||||
return this.originalId;
|
||||
}
|
||||
|
||||
void setOriginalId(String originalId) {
|
||||
this.originalId = originalId;
|
||||
}
|
||||
|
||||
public String changeSessionId() {
|
||||
String changedId = generateId();
|
||||
setId(changedId);
|
||||
return changedId;
|
||||
}
|
||||
|
||||
public Instant getLastAccessedTime() {
|
||||
return this.lastAccessedTime;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
public void setMaxInactiveInterval(Duration interval) {
|
||||
this.maxInactiveInterval = interval;
|
||||
}
|
||||
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
public Duration getMaxInactiveInterval() {
|
||||
return this.maxInactiveInterval;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return isExpired(System.currentTimeMillis());
|
||||
return isExpired(Instant.now());
|
||||
}
|
||||
|
||||
boolean isExpired(long now) {
|
||||
if (this.maxInactiveInterval < 0) {
|
||||
boolean isExpired(Instant now) {
|
||||
if (this.maxInactiveInterval.isNegative()) {
|
||||
return false;
|
||||
}
|
||||
return now - TimeUnit.SECONDS
|
||||
.toMillis(this.maxInactiveInterval) >= this.lastAccessedTime;
|
||||
return now.minus(this.maxInactiveInterval).compareTo(this.lastAccessedTime) >= 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -158,12 +179,11 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time that this {@link Session} was created in milliseconds since midnight
|
||||
* of 1/1/1970 GMT. The default is when the {@link Session} was instantiated.
|
||||
* @param creationTime the time that this {@link Session} was created in milliseconds
|
||||
* since midnight of 1/1/1970 GMT.
|
||||
* Sets the time that this {@link Session} was created. The default is when the
|
||||
* {@link Session} was instantiated.
|
||||
* @param creationTime the time that this {@link Session} was created.
|
||||
*/
|
||||
public void setCreationTime(long creationTime) {
|
||||
public void setCreationTime(Instant creationTime) {
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
|
||||
@@ -186,5 +206,9 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
private static String generateId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7160779239673823561L;
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -36,14 +37,14 @@ import org.springframework.session.events.SessionExpiredEvent;
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MapSessionRepository implements SessionRepository<ExpiringSession> {
|
||||
public class MapSessionRepository implements SessionRepository<MapSession> {
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
|
||||
private final Map<String, ExpiringSession> sessions;
|
||||
private final Map<String, Session> sessions;
|
||||
|
||||
/**
|
||||
* Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}.
|
||||
@@ -58,7 +59,7 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
|
||||
*
|
||||
* @param sessions the {@link java.util.Map} to use. Cannot be null.
|
||||
*/
|
||||
public MapSessionRepository(Map<String, ExpiringSession> sessions) {
|
||||
public MapSessionRepository(Map<String, Session> sessions) {
|
||||
if (sessions == null) {
|
||||
throw new IllegalArgumentException("sessions cannot be null");
|
||||
}
|
||||
@@ -67,7 +68,7 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override
|
||||
* {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
* {@link Session#setMaxInactiveInterval(Duration)}.
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session}
|
||||
* should be kept alive between client requests.
|
||||
*/
|
||||
@@ -75,30 +76,35 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
|
||||
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
|
||||
}
|
||||
|
||||
public void save(ExpiringSession session) {
|
||||
public void save(MapSession session) {
|
||||
if (!session.getId().equals(session.getOriginalId())) {
|
||||
this.sessions.remove(session.getOriginalId());
|
||||
session.setOriginalId(session.getId());
|
||||
}
|
||||
this.sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
public ExpiringSession getSession(String id) {
|
||||
ExpiringSession saved = this.sessions.get(id);
|
||||
public MapSession findById(String id) {
|
||||
Session saved = this.sessions.get(id);
|
||||
if (saved == null) {
|
||||
return null;
|
||||
}
|
||||
if (saved.isExpired()) {
|
||||
delete(saved.getId());
|
||||
deleteById(saved.getId());
|
||||
return null;
|
||||
}
|
||||
return new MapSession(saved);
|
||||
}
|
||||
|
||||
public void delete(String id) {
|
||||
public void deleteById(String id) {
|
||||
this.sessions.remove(id);
|
||||
}
|
||||
|
||||
public ExpiringSession createSession() {
|
||||
ExpiringSession result = new MapSession();
|
||||
public MapSession createSession() {
|
||||
MapSession result = new MapSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval);
|
||||
result.setMaxInactiveInterval(
|
||||
Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* A repository interface for managing {@link Session} instances.
|
||||
*
|
||||
* @param <S> the {@link Session} type
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ReactorSessionRepository<S extends Session> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Session} that is capable of being persisted by this
|
||||
* {@link ReactorSessionRepository}.
|
||||
*
|
||||
* <p>
|
||||
* This allows optimizations and customizations in how the {@link Session} is
|
||||
* persisted. For example, the implementation returned might keep track of the changes
|
||||
* ensuring that only the delta needs to be persisted on a save.
|
||||
* </p>
|
||||
*
|
||||
* @return a new {@link Session} that is capable of being persisted by this
|
||||
* {@link ReactorSessionRepository}
|
||||
*/
|
||||
Mono<S> createSession();
|
||||
|
||||
/**
|
||||
* Ensures the {@link Session} created by
|
||||
* {@link ReactorSessionRepository#createSession()} is saved.
|
||||
*
|
||||
* <p>
|
||||
* Some implementations may choose to save as the {@link Session} is updated by
|
||||
* returning a {@link Session} that immediately persists any changes. In this case,
|
||||
* this method may not actually do anything.
|
||||
* </p>
|
||||
*
|
||||
* @param session the {@link Session} to save
|
||||
* @return indicator of operation completion
|
||||
*/
|
||||
Mono<Void> save(S session);
|
||||
|
||||
/**
|
||||
* Gets the {@link Session} by the {@link Session#getId()} or null if no
|
||||
* {@link Session} is found.
|
||||
*
|
||||
* @param id the {@link Session#getId()} to lookup
|
||||
* @return the {@link Session} by the {@link Session#getId()} or null if no
|
||||
* {@link Session} is found.
|
||||
*/
|
||||
Mono<S> findById(String id);
|
||||
|
||||
/**
|
||||
* Deletes the {@link Session} with the given {@link Session#getId()} or does nothing
|
||||
* if the {@link Session} is not found.
|
||||
* @param id the {@link Session#getId()} to delete
|
||||
* @return indicator of operation completion
|
||||
*/
|
||||
Mono<Void> delete(String id);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides a way to identify a user in an agnostic way. This allows the session to be
|
||||
* used by an HttpSession, WebSocket Session, or even non web related sessions.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Vedran Pavic
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Session {
|
||||
|
||||
/**
|
||||
* Gets a unique string that identifies the {@link Session}.
|
||||
*
|
||||
* @return a unique string that identifies the {@link Session}
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Changes the session id. After invoking the {@link #getId()} will return a new identifier.
|
||||
* @return the new session id which {@link #getId()} will now return
|
||||
*/
|
||||
String changeSessionId();
|
||||
|
||||
/**
|
||||
* Gets the Object associated with the specified name or null if no Object is
|
||||
* associated to that name.
|
||||
*
|
||||
* @param <T> The return type of the attribute
|
||||
* @param attributeName the name of the attribute to get
|
||||
* @return the Object associated with the specified name or null if no Object is
|
||||
* associated to that name
|
||||
*/
|
||||
<T> T getAttribute(String attributeName);
|
||||
|
||||
/**
|
||||
* Return the session attribute value or if not present raise an
|
||||
* {@link IllegalArgumentException}.
|
||||
* @param name the attribute name
|
||||
* @param <T> the attribute type
|
||||
* @return the attribute value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T> T getRequiredAttribute(String name) {
|
||||
T result = getAttribute(name);
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Required attribute '" + name + "' is missing.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session attribute value, or a default, fallback value.
|
||||
* @param name the attribute name
|
||||
* @param defaultValue a default value to return instead
|
||||
* @param <T> the attribute type
|
||||
* @return the attribute value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T> T getAttributeOrDefault(String name, T defaultValue) {
|
||||
T result = getAttribute(name);
|
||||
return result == null ? defaultValue : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the attribute names that have a value associated with it. Each value can be
|
||||
* passed into {@link org.springframework.session.Session#getAttribute(String)} to
|
||||
* obtain the attribute value.
|
||||
*
|
||||
* @return the attribute names that have a value associated with it.
|
||||
* @see #getAttribute(String)
|
||||
*/
|
||||
Set<String> getAttributeNames();
|
||||
|
||||
/**
|
||||
* Sets the attribute value for the provided attribute name. If the attributeValue is
|
||||
* null, it has the same result as removing the attribute with
|
||||
* {@link org.springframework.session.Session#removeAttribute(String)} .
|
||||
*
|
||||
* @param attributeName the attribute name to set
|
||||
* @param attributeValue the value of the attribute to set. If null, the attribute
|
||||
* will be removed.
|
||||
*/
|
||||
void setAttribute(String attributeName, Object attributeValue);
|
||||
|
||||
/**
|
||||
* Removes the attribute with the provided attribute name.
|
||||
* @param attributeName the name of the attribute to remove
|
||||
*/
|
||||
void removeAttribute(String attributeName);
|
||||
|
||||
/**
|
||||
* Gets the time when this session was created.
|
||||
*
|
||||
* @return the time when this session was created.
|
||||
*/
|
||||
Instant getCreationTime();
|
||||
|
||||
/**
|
||||
* Sets the last accessed time.
|
||||
*
|
||||
* @param lastAccessedTime the last accessed time
|
||||
*/
|
||||
void setLastAccessedTime(Instant lastAccessedTime);
|
||||
|
||||
/**
|
||||
* Gets the last time this {@link Session} was accessed.
|
||||
*
|
||||
* @return the last time the client sent a request associated with the session
|
||||
*/
|
||||
Instant getLastAccessedTime();
|
||||
|
||||
/**
|
||||
* Sets the maximum inactive interval between requests before this session will be
|
||||
* invalidated. A negative time indicates that the session will never timeout.
|
||||
*
|
||||
* @param interval the amount of time that the {@link Session} should be kept alive
|
||||
* between client requests.
|
||||
*/
|
||||
void setMaxInactiveInterval(Duration interval);
|
||||
|
||||
/**
|
||||
* Gets the maximum inactive interval between requests before this session will be
|
||||
* invalidated. A negative time indicates that the session will never timeout.
|
||||
*
|
||||
* @return the maximum inactive interval between requests before this session will be
|
||||
* invalidated. A negative time indicates that the session will never timeout.
|
||||
*/
|
||||
Duration getMaxInactiveInterval();
|
||||
|
||||
/**
|
||||
* Returns true if the session is expired.
|
||||
*
|
||||
* @return true if the session is expired, else false.
|
||||
*/
|
||||
boolean isExpired();
|
||||
|
||||
}
|
||||
@@ -62,12 +62,12 @@ public interface SessionRepository<S extends Session> {
|
||||
* @return the {@link Session} by the {@link Session#getId()} or null if no
|
||||
* {@link Session} is found.
|
||||
*/
|
||||
S getSession(String id);
|
||||
S findById(String id);
|
||||
|
||||
/**
|
||||
* Deletes the {@link Session} with the given {@link Session#getId()} or does nothing
|
||||
* if the {@link Session} is not found.
|
||||
* @param id the {@link org.springframework.session.Session#getId()} to delete
|
||||
*/
|
||||
void delete(String id);
|
||||
void deleteById(String id);
|
||||
}
|
||||
@@ -21,15 +21,19 @@ import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDestroyedEvent;
|
||||
@@ -91,6 +95,8 @@ import org.springframework.util.ObjectUtils;
|
||||
@Configuration
|
||||
public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private CookieHttpSessionStrategy defaultHttpSessionStrategy = new CookieHttpSessionStrategy();
|
||||
|
||||
private boolean usesSpringSessionRememberMeServices;
|
||||
@@ -105,15 +111,9 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (this.cookieSerializer != null) {
|
||||
this.defaultHttpSessionStrategy.setCookieSerializer(this.cookieSerializer);
|
||||
}
|
||||
else if (this.usesSpringSessionRememberMeServices) {
|
||||
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
|
||||
cookieSerializer.setRememberMeRequestAttribute(
|
||||
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);
|
||||
this.defaultHttpSessionStrategy.setCookieSerializer(cookieSerializer);
|
||||
}
|
||||
CookieSerializer cookieSerializer = this.cookieSerializer != null
|
||||
? this.cookieSerializer : createDefaultCookieSerializer();
|
||||
this.defaultHttpSessionStrategy.setCookieSerializer(cookieSerializer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -122,7 +122,7 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
|
||||
public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(
|
||||
SessionRepository<S> sessionRepository) {
|
||||
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(
|
||||
sessionRepository);
|
||||
@@ -168,4 +168,37 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
this.httpSessionListeners = listeners;
|
||||
}
|
||||
|
||||
private CookieSerializer createDefaultCookieSerializer() {
|
||||
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
|
||||
if (this.servletContext != null) {
|
||||
SessionCookieConfig sessionCookieConfig = null;
|
||||
try {
|
||||
sessionCookieConfig = this.servletContext.getSessionCookieConfig();
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
this.logger
|
||||
.warn("Unable to obtain SessionCookieConfig: " + e.getMessage());
|
||||
}
|
||||
if (sessionCookieConfig != null) {
|
||||
if (sessionCookieConfig.getName() != null) {
|
||||
cookieSerializer.setCookieName(sessionCookieConfig.getName());
|
||||
}
|
||||
if (sessionCookieConfig.getDomain() != null) {
|
||||
cookieSerializer.setDomainName(sessionCookieConfig.getDomain());
|
||||
}
|
||||
if (sessionCookieConfig.getPath() != null) {
|
||||
cookieSerializer.setCookiePath(sessionCookieConfig.getPath());
|
||||
}
|
||||
if (sessionCookieConfig.getMaxAge() != -1) {
|
||||
cookieSerializer.setCookieMaxAge(sessionCookieConfig.getMaxAge());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.usesSpringSessionRememberMeServices) {
|
||||
cookieSerializer.setRememberMeRequestAttribute(
|
||||
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);
|
||||
}
|
||||
return cookieSerializer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.session.SessionInformation;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
@@ -32,12 +31,12 @@ import org.springframework.session.SessionRepository;
|
||||
* Ensures that calling {@link #expireNow()} propagates to Spring Session, since this
|
||||
* session information contains only derived data and is not the authoritative source.
|
||||
*
|
||||
* @param <S> the {@link ExpiringSession} type.
|
||||
* @param <S> the {@link Session} type.
|
||||
* @author Joris Kuipers
|
||||
* @author Vedran Pavic
|
||||
* @since 1.3
|
||||
*/
|
||||
class SpringSessionBackedSessionInformation<S extends ExpiringSession>
|
||||
class SpringSessionBackedSessionInformation<S extends Session>
|
||||
extends SessionInformation {
|
||||
|
||||
static final String EXPIRED_ATTR = SpringSessionBackedSessionInformation.class
|
||||
@@ -53,9 +52,10 @@ class SpringSessionBackedSessionInformation<S extends ExpiringSession>
|
||||
SpringSessionBackedSessionInformation(S session,
|
||||
SessionRepository<S> sessionRepository) {
|
||||
super(resolvePrincipal(session), session.getId(),
|
||||
new Date(session.getLastAccessedTime()));
|
||||
Date.from(session.getLastAccessedTime()));
|
||||
this.sessionRepository = sessionRepository;
|
||||
if (Boolean.TRUE.equals(session.getAttribute(EXPIRED_ATTR))) {
|
||||
Boolean expired = session.getAttribute(EXPIRED_ATTR);
|
||||
if (Boolean.TRUE.equals(expired)) {
|
||||
super.expireNow();
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,10 @@ class SpringSessionBackedSessionInformation<S extends ExpiringSession>
|
||||
if (principalName != null) {
|
||||
return principalName;
|
||||
}
|
||||
SecurityContext securityContext = session.getAttribute(SPRING_SECURITY_CONTEXT);
|
||||
if (securityContext != null && securityContext.getAuthentication() != null) {
|
||||
SecurityContext securityContext = session
|
||||
.getAttribute(SPRING_SECURITY_CONTEXT);
|
||||
if (securityContext != null
|
||||
&& securityContext.getAuthentication() != null) {
|
||||
return securityContext.getAuthentication().getName();
|
||||
}
|
||||
return "";
|
||||
@@ -87,7 +89,7 @@ class SpringSessionBackedSessionInformation<S extends ExpiringSession>
|
||||
+ "sessions was exceeded");
|
||||
}
|
||||
super.expireNow();
|
||||
S session = this.sessionRepository.getSession(getSessionId());
|
||||
S session = this.sessionRepository.findById(getSessionId());
|
||||
if (session != null) {
|
||||
session.setAttribute(EXPIRED_ATTR, Boolean.TRUE);
|
||||
this.sessionRepository.save(session);
|
||||
@@ -24,8 +24,8 @@ import java.util.List;
|
||||
import org.springframework.security.core.session.SessionInformation;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -39,12 +39,12 @@ import org.springframework.util.Assert;
|
||||
* <p>
|
||||
* Does not support {@link #getAllPrincipals()}, since that information is not available.
|
||||
*
|
||||
* @param <S> the {@link ExpiringSession} type.
|
||||
* @param <S> the {@link Session} type.
|
||||
* @author Joris Kuipers
|
||||
* @author Vedran Pavic
|
||||
* @since 1.3
|
||||
*/
|
||||
public class SpringSessionBackedSessionRegistry<S extends ExpiringSession>
|
||||
public class SpringSessionBackedSessionRegistry<S extends Session>
|
||||
implements SessionRegistry {
|
||||
|
||||
private final FindByIndexNameSessionRepository<S> sessionRepository;
|
||||
@@ -70,7 +70,7 @@ public class SpringSessionBackedSessionRegistry<S extends ExpiringSession>
|
||||
for (S session : sessions) {
|
||||
if (includeExpiredSessions || !Boolean.TRUE.equals(session
|
||||
.getAttribute(SpringSessionBackedSessionInformation.EXPIRED_ATTR))) {
|
||||
infos.add(new SpringSessionBackedSessionInformation<S>(session,
|
||||
infos.add(new SpringSessionBackedSessionInformation<>(session,
|
||||
this.sessionRepository));
|
||||
}
|
||||
}
|
||||
@@ -78,9 +78,9 @@ public class SpringSessionBackedSessionRegistry<S extends ExpiringSession>
|
||||
}
|
||||
|
||||
public SessionInformation getSessionInformation(String sessionId) {
|
||||
S session = this.sessionRepository.getSession(sessionId);
|
||||
S session = this.sessionRepository.findById(sessionId);
|
||||
if (session != null) {
|
||||
return new SpringSessionBackedSessionInformation<S>(session,
|
||||
return new SpringSessionBackedSessionInformation<>(session,
|
||||
this.sessionRepository);
|
||||
}
|
||||
return null;
|
||||
@@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.web.http.CookieSerializer.CookieValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link HttpSessionStrategy} that uses a cookie to obtain the session from.
|
||||
@@ -121,7 +120,7 @@ import org.springframework.util.Assert;
|
||||
* entry.getValue();
|
||||
* </code>
|
||||
*
|
||||
* Session session = repo.getSession(sessionId); if(session == null) { continue; }
|
||||
* Session session = repo.findById(sessionId); if(session == null) { continue; }
|
||||
*
|
||||
* String username = session.getAttribute("username"); if(username == null) {
|
||||
* newSessionAlias = alias; continue; }
|
||||
@@ -251,18 +250,18 @@ public final class CookieHttpSessionStrategy
|
||||
return sessionIds.values().iterator().next();
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : sessionIds.entrySet()) {
|
||||
String alias = entry.getKey();
|
||||
String id = entry.getValue();
|
||||
|
||||
buffer.append(alias);
|
||||
buffer.append(this.serializationDelimiter);
|
||||
buffer.append(id);
|
||||
buffer.append(this.serializationDelimiter);
|
||||
sb.append(alias);
|
||||
sb.append(this.serializationDelimiter);
|
||||
sb.append(id);
|
||||
sb.append(this.serializationDelimiter);
|
||||
}
|
||||
buffer.deleteCharAt(buffer.length() - 1);
|
||||
return buffer.toString();
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void onInvalidateSession(HttpServletRequest request,
|
||||
@@ -293,7 +292,9 @@ public final class CookieHttpSessionStrategy
|
||||
* @param cookieSerializer the cookieSerializer to set. Cannot be null.
|
||||
*/
|
||||
public void setCookieSerializer(CookieSerializer cookieSerializer) {
|
||||
Assert.notNull(cookieSerializer, "cookieSerializer cannot be null");
|
||||
if (cookieSerializer == null) {
|
||||
throw new IllegalArgumentException("cookieSerializer cannot be null");
|
||||
}
|
||||
this.cookieSerializer = cookieSerializer;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link HttpSessionStrategy} that uses a header to obtain the session from.
|
||||
@@ -79,7 +78,9 @@ public class HeaderHttpSessionStrategy implements HttpSessionStrategy {
|
||||
* @param headerName the name of the header to obtain the session id from.
|
||||
*/
|
||||
public void setHeaderName(String headerName) {
|
||||
Assert.notNull(headerName, "headerName cannot be null");
|
||||
if (headerName == null) {
|
||||
throw new IllegalArgumentException("headerName cannot be null");
|
||||
}
|
||||
this.headerName = headerName;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2017 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.web.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -25,23 +26,23 @@ import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionContext;
|
||||
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
|
||||
/**
|
||||
* Adapts Spring Session's {@link ExpiringSession} to an {@link HttpSession}.
|
||||
* Adapts Spring Session's {@link Session} to an {@link HttpSession}.
|
||||
*
|
||||
* @param <S> the {@link ExpiringSession} type
|
||||
* @param <S> the {@link Session} type
|
||||
* @author Rob Winch
|
||||
* @since 1.1
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSession {
|
||||
class HttpSessionAdapter<S extends Session> implements HttpSession {
|
||||
private S session;
|
||||
private final ServletContext servletContext;
|
||||
private boolean invalidated;
|
||||
private boolean old;
|
||||
|
||||
ExpiringSessionHttpSession(S session, ServletContext servletContext) {
|
||||
HttpSessionAdapter(S session, ServletContext servletContext) {
|
||||
this.session = session;
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
@@ -56,7 +57,7 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
|
||||
|
||||
public long getCreationTime() {
|
||||
checkState();
|
||||
return this.session.getCreationTime();
|
||||
return this.session.getCreationTime().toEpochMilli();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@@ -65,7 +66,7 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
checkState();
|
||||
return this.session.getLastAccessedTime();
|
||||
return this.session.getLastAccessedTime().toEpochMilli();
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
@@ -73,11 +74,11 @@ class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSessi
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(int interval) {
|
||||
this.session.setMaxInactiveIntervalInSeconds(interval);
|
||||
this.session.setMaxInactiveInterval(Duration.ofSeconds(interval));
|
||||
}
|
||||
|
||||
public int getMaxInactiveInterval() {
|
||||
return this.session.getMaxInactiveIntervalInSeconds();
|
||||
return (int) this.session.getMaxInactiveInterval().getSeconds();
|
||||
}
|
||||
|
||||
public HttpSessionContext getSessionContext() {
|
||||
@@ -24,7 +24,7 @@ import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.events.AbstractSessionEvent;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDestroyedEvent;
|
||||
@@ -73,8 +73,8 @@ public class SessionEventHttpSessionListenerAdapter
|
||||
}
|
||||
|
||||
private HttpSessionEvent createHttpSessionEvent(AbstractSessionEvent event) {
|
||||
ExpiringSession session = event.getSession();
|
||||
HttpSession httpSession = new ExpiringSessionHttpSession<>(session,
|
||||
Session session = event.getSession();
|
||||
HttpSession httpSession = new HttpSessionAdapter<>(session,
|
||||
this.context);
|
||||
HttpSessionEvent httpSessionEvent = new HttpSessionEvent(httpSession);
|
||||
return httpSessionEvent;
|
||||
@@ -17,9 +17,7 @@
|
||||
package org.springframework.session.web.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletContext;
|
||||
@@ -33,7 +31,6 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
|
||||
@@ -56,7 +53,7 @@ import org.springframework.session.SessionRepository;
|
||||
* <li>The session id is looked up using
|
||||
* {@link HttpSessionStrategy#getRequestedSessionId(javax.servlet.http.HttpServletRequest)}
|
||||
* . The default is to look in a cookie named SESSION.</li>
|
||||
* <li>The session id of newly created {@link org.springframework.session.ExpiringSession}
|
||||
* <li>The session id of newly created {@link org.springframework.session.Session}
|
||||
* is sent to the client using
|
||||
* <li>The client is notified that the session id is no longer valid with
|
||||
* {@link HttpSessionStrategy#onInvalidateSession(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
|
||||
@@ -69,12 +66,12 @@ import org.springframework.session.SessionRepository;
|
||||
* persisted properly.
|
||||
* </p>
|
||||
*
|
||||
* @param <S> the {@link ExpiringSession} type.
|
||||
* @param <S> the {@link Session} type.
|
||||
* @since 1.0
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
|
||||
public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
public class SessionRepositoryFilter<S extends Session>
|
||||
extends OncePerRequestFilter {
|
||||
private static final String SESSION_LOGGER_NAME = SessionRepositoryFilter.class
|
||||
.getName().concat(".SESSION_LOGGER");
|
||||
@@ -274,30 +271,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
"Cannot change session ID. There is no session associated with this request.");
|
||||
}
|
||||
|
||||
// eagerly get session attributes in case implementation lazily loads them
|
||||
Map<String, Object> attrs = new HashMap<>();
|
||||
Enumeration<String> iAttrNames = session.getAttributeNames();
|
||||
while (iAttrNames.hasMoreElements()) {
|
||||
String attrName = iAttrNames.nextElement();
|
||||
Object value = session.getAttribute(attrName);
|
||||
|
||||
attrs.put(attrName, value);
|
||||
}
|
||||
|
||||
SessionRepositoryFilter.this.sessionRepository.delete(session.getId());
|
||||
HttpSessionWrapper original = getCurrentSession();
|
||||
setCurrentSession(null);
|
||||
|
||||
HttpSessionWrapper newSession = getSession();
|
||||
original.setSession(newSession.getSession());
|
||||
|
||||
newSession.setMaxInactiveInterval(session.getMaxInactiveInterval());
|
||||
for (Map.Entry<String, Object> attr : attrs.entrySet()) {
|
||||
String attrName = attr.getKey();
|
||||
Object attrValue = attr.getValue();
|
||||
newSession.setAttribute(attrName, attrValue);
|
||||
}
|
||||
return newSession.getId();
|
||||
return getCurrentSession().getSession().changeSessionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -324,11 +298,11 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
|
||||
private S getSession(String sessionId) {
|
||||
S session = SessionRepositoryFilter.this.sessionRepository
|
||||
.getSession(sessionId);
|
||||
.findById(sessionId);
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
session.setLastAccessedTime(Instant.now());
|
||||
return session;
|
||||
}
|
||||
|
||||
@@ -370,7 +344,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
"For debugging purposes only (not an error)"));
|
||||
}
|
||||
S session = SessionRepositoryFilter.this.sessionRepository.createSession();
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
session.setLastAccessedTime(Instant.now());
|
||||
currentSession = new HttpSessionWrapper(session, getServletContext());
|
||||
setCurrentSession(currentSession);
|
||||
return currentSession;
|
||||
@@ -402,7 +376,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class HttpSessionWrapper extends ExpiringSessionHttpSession<S> {
|
||||
private final class HttpSessionWrapper extends HttpSessionAdapter<S> {
|
||||
|
||||
HttpSessionWrapper(S session, ServletContext servletContext) {
|
||||
super(session, servletContext);
|
||||
@@ -413,7 +387,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
super.invalidate();
|
||||
SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true;
|
||||
setCurrentSession(null);
|
||||
SessionRepositoryFilter.this.sessionRepository.delete(getId());
|
||||
SessionRepositoryFilter.this.sessionRepository.deleteById(getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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
|
||||
*
|
||||
* http://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.web.server.session;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.session.ReactorSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import org.springframework.web.server.session.CookieWebSessionIdResolver;
|
||||
import org.springframework.web.server.session.WebSessionIdResolver;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
import org.springframework.web.server.session.WebSessionStore;
|
||||
|
||||
/**
|
||||
* The {@link WebSessionManager} implementation backed by
|
||||
* {@link ReactorSessionRepository}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
|
||||
private final SpringSessionWebSessionStore<? extends Session> sessionStore;
|
||||
|
||||
private WebSessionIdResolver sessionIdResolver = new CookieWebSessionIdResolver();
|
||||
|
||||
private Clock clock = Clock.system(ZoneOffset.UTC);
|
||||
|
||||
public SpringSessionWebSessionManager(
|
||||
ReactorSessionRepository<? extends Session> sessionRepository) {
|
||||
this.sessionStore = new SpringSessionWebSessionStore<>(sessionRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured {@link WebSessionIdResolver}.
|
||||
* @return the configured {@link WebSessionIdResolver}
|
||||
*/
|
||||
private WebSessionIdResolver getSessionIdResolver() {
|
||||
return this.sessionIdResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the id resolution strategy.
|
||||
* <p>
|
||||
* By default an instance of {@link CookieWebSessionIdResolver}.
|
||||
* @param sessionIdResolver the resolver to use
|
||||
*/
|
||||
public void setSessionIdResolver(WebSessionIdResolver sessionIdResolver) {
|
||||
Assert.notNull(sessionIdResolver, "WebSessionIdResolver is required.");
|
||||
this.sessionIdResolver = sessionIdResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured {@link WebSessionStore}.
|
||||
* @return the configured {@link WebSessionStore}
|
||||
*/
|
||||
private WebSessionStore getSessionStore() {
|
||||
return this.sessionStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured clock for session {@code lastAccessTime} calculations.
|
||||
* @return the configured clock for session {@code lastAccessTime} calculations
|
||||
*/
|
||||
private Clock getClock() {
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link Clock} to use to set lastAccessTime on every created session
|
||||
* and to calculate if it is expired.
|
||||
* <p>
|
||||
* This may be useful to align to different timezone or to set the clock back in a
|
||||
* test, e.g. {@code Clock.offset(clock, Duration.ofMinutes(-31))} in order to
|
||||
* simulate session expiration.
|
||||
* <p>
|
||||
* By default this is {@code Clock.system(ZoneOffset.UTC)}.
|
||||
* @param clock the clock to use
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
Assert.notNull(clock, "'clock' is required.");
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<WebSession> getSession(ServerWebExchange exchange) {
|
||||
// @formatter:off
|
||||
return Mono.defer(() ->
|
||||
retrieveSession(exchange)
|
||||
.flatMap(session -> removeSessionIfExpired(exchange, session))
|
||||
.flatMap(session -> {
|
||||
Instant lastAccessTime = Instant.now(getClock());
|
||||
return this.sessionStore.setLastAccessedTime(session, lastAccessTime);
|
||||
})
|
||||
.switchIfEmpty(createSession(exchange))
|
||||
.doOnNext(session -> exchange.getResponse().beforeCommit(session::save)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<WebSession> retrieveSession(ServerWebExchange exchange) {
|
||||
// @formatter:off
|
||||
return Flux.fromIterable(getSessionIdResolver().resolveSessionIds(exchange))
|
||||
.concatMap(this.sessionStore::retrieveSession)
|
||||
.cast(WebSession.class)
|
||||
.next();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<WebSession> removeSessionIfExpired(ServerWebExchange exchange,
|
||||
WebSession session) {
|
||||
if (session.isExpired()) {
|
||||
this.sessionIdResolver.expireSession(exchange);
|
||||
return this.sessionStore.removeSession(session.getId()).then(Mono.empty());
|
||||
}
|
||||
return Mono.just(session);
|
||||
}
|
||||
|
||||
private Mono<Void> saveSession(ServerWebExchange exchange, WebSession session) {
|
||||
if (session.isExpired()) {
|
||||
return Mono.error(new IllegalStateException(
|
||||
"Sessions are checked for expiration and have their "
|
||||
+ "lastAccessTime updated when first accessed during request processing. "
|
||||
+ "However this session is expired meaning that maxIdleTime elapsed "
|
||||
+ "before the call to session.save()."));
|
||||
}
|
||||
|
||||
if (!session.isStarted()) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
// Force explicit start
|
||||
session.start();
|
||||
|
||||
if (hasNewSessionId(exchange, session)) {
|
||||
this.sessionIdResolver.setSessionId(exchange, session.getId());
|
||||
}
|
||||
|
||||
return this.sessionStore.storeSession(session);
|
||||
}
|
||||
|
||||
private boolean hasNewSessionId(ServerWebExchange exchange, WebSession session) {
|
||||
List<String> ids = getSessionIdResolver().resolveSessionIds(exchange);
|
||||
return ids.isEmpty() || !session.getId().equals(ids.get(0));
|
||||
}
|
||||
|
||||
private Mono<WebSession> createSession(ServerWebExchange exchange) {
|
||||
return this.sessionStore.createSession();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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
|
||||
*
|
||||
* http://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.web.server.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.session.ReactorSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import org.springframework.web.server.session.WebSessionStore;
|
||||
|
||||
/**
|
||||
* The {@link WebSessionStore} implementation that provides the {@link WebSession}
|
||||
* implementation backed by a {@link Session} returned by the
|
||||
* {@link ReactorSessionRepository}.
|
||||
*
|
||||
* @param <S> the {@link Session} type
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore {
|
||||
|
||||
private final ReactorSessionRepository<S> sessions;
|
||||
|
||||
SpringSessionWebSessionStore(ReactorSessionRepository<S> sessions) {
|
||||
Assert.notNull(sessions, "sessions cannot be null");
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
public Mono<WebSession> createSession() {
|
||||
return this.sessions.createSession().map(this::createSession);
|
||||
}
|
||||
|
||||
public Mono<WebSession> setLastAccessedTime(WebSession session,
|
||||
Instant lastAccessedTime) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SpringSessionWebSession springSessionWebSession = (SpringSessionWebSession) session;
|
||||
springSessionWebSession.session.setLastAccessedTime(lastAccessedTime);
|
||||
return Mono.just(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> storeSession(WebSession session) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SpringSessionWebSession springWebSession = (SpringSessionWebSession) session;
|
||||
return this.sessions.save(springWebSession.session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<WebSession> retrieveSession(String sessionId) {
|
||||
return this.sessions.findById(sessionId).map(this::existingSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> changeSessionId(String s, WebSession webSession) {
|
||||
return storeSession(webSession);
|
||||
}
|
||||
|
||||
private SpringSessionWebSession createSession(S session) {
|
||||
return new SpringSessionWebSession(session, State.NEW);
|
||||
}
|
||||
|
||||
private SpringSessionWebSession existingSession(S session) {
|
||||
return new SpringSessionWebSession(session, State.STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> removeSession(String sessionId) {
|
||||
return this.sessions.delete(sessionId);
|
||||
}
|
||||
|
||||
private enum State {
|
||||
NEW, STARTED
|
||||
}
|
||||
|
||||
private static class SpringSessionMap implements Map<String, Object> {
|
||||
|
||||
private final Session session;
|
||||
|
||||
private final Collection<Object> values = new SessionValues();
|
||||
|
||||
SpringSessionMap(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.session.getAttributeNames().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.session.getAttributeNames().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return key instanceof String
|
||||
&& this.session.getAttributeNames().contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.session.getAttributeNames().stream()
|
||||
.anyMatch(attrName -> this.session.getAttribute(attrName) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object get(Object key) {
|
||||
if (key instanceof String) {
|
||||
return this.session.getAttribute((String) key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
Object original = this.session.getAttribute(key);
|
||||
this.session.setAttribute(key, value);
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object remove(Object key) {
|
||||
if (key instanceof String) {
|
||||
String attrName = (String) key;
|
||||
Object original = this.session.getAttribute(attrName);
|
||||
this.session.removeAttribute(attrName);
|
||||
return original;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ?> m) {
|
||||
for (Entry<? extends String, ?> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
for (String attrName : this.session.getAttributeNames()) {
|
||||
remove(attrName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return this.session.getAttributeNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return this.values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
Set<String> attrNames = keySet();
|
||||
Set<Entry<String, Object>> entries = new HashSet<>(attrNames.size());
|
||||
for (String attrName : attrNames) {
|
||||
Object value = this.session.getAttribute(attrName);
|
||||
entries.add(new AbstractMap.SimpleEntry<>(attrName, value));
|
||||
}
|
||||
return Collections.unmodifiableSet(entries);
|
||||
}
|
||||
|
||||
private class SessionValues extends AbstractCollection<Object> {
|
||||
|
||||
public Iterator<Object> iterator() {
|
||||
return new Iterator<Object>() {
|
||||
|
||||
private Iterator<Entry<String, Object>> i = entrySet().iterator();
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.i.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return this.i.next().getValue();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.i.remove();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return SpringSessionMap.this.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return SpringSessionMap.this.isEmpty();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
SpringSessionMap.this.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object v) {
|
||||
return SpringSessionMap.this.containsValue(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts Spring Session's {@link Session} to a {@link WebSession}.
|
||||
*/
|
||||
private class SpringSessionWebSession implements WebSession {
|
||||
|
||||
private final S session;
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
private AtomicReference<State> state = new AtomicReference<>();
|
||||
|
||||
private volatile transient Supplier<Mono<Void>> saveOperation = Mono::empty;
|
||||
|
||||
SpringSessionWebSession(S session, State state) {
|
||||
Assert.notNull(session, "session cannot be null");
|
||||
this.session = session;
|
||||
this.attributes = new SpringSessionMap(session);
|
||||
this.state.set(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.session.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> changeSessionId() {
|
||||
return Mono.defer(() -> {
|
||||
this.session.changeSessionId();
|
||||
return save();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.state.compareAndSet(State.NEW, State.STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
State value = this.state.get();
|
||||
return (State.STARTED.equals(value)
|
||||
|| (State.NEW.equals(value) && !getAttributes().isEmpty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save() {
|
||||
return this.saveOperation.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
return this.session.isExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getCreationTime() {
|
||||
return this.session.getCreationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getLastAccessTime() {
|
||||
return this.session.getLastAccessedTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getMaxIdleTime() {
|
||||
return this.session.getMaxInactiveInterval();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTime(Duration maxIdleTime) {
|
||||
this.session.setMaxInactiveInterval(maxIdleTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,18 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.config;
|
||||
/**
|
||||
* Spring Session reactive web support.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.session.web.server.session;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
|
||||
@Configuration
|
||||
public class DataSourceConfig {
|
||||
|
||||
@Bean
|
||||
public LettuceConnectionFactory connectionFactory() {
|
||||
return new LettuceConnectionFactory();
|
||||
}
|
||||
|
||||
}
|
||||
import org.springframework.lang.NonNullApi;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user