Add auto-configuration support for Spring Session
This commit adds support for automatically configuring Spring Session. In a web application when both Spring Session and Spring Data Redis are on the classpath, Spring Session's Redis Http Session support will be auto-configured. The max inactive interval for Redis-backed sessions can be configured via the environment using the existing server.session-timeout property. Closes gh-2318
This commit is contained in:
parent
dc6a2f057c
commit
fd6d61e8b4
|
@ -400,6 +400,11 @@
|
||||||
<artifactId>spring-security-jwt</artifactId>
|
<artifactId>spring-security-jwt</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.session</groupId>
|
||||||
|
<artifactId>spring-session</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.amqp</groupId>
|
<groupId>org.springframework.amqp</groupId>
|
||||||
<artifactId>spring-rabbit</artifactId>
|
<artifactId>spring-rabbit</artifactId>
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2015 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.boot.autoconfigure.session;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.session.Session;
|
||||||
|
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
|
||||||
|
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||||
|
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for Spring Session.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 1.3.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(Session.class)
|
||||||
|
@EnableConfigurationProperties(ServerProperties.class)
|
||||||
|
@AutoConfigureAfter(RedisAutoConfiguration.class)
|
||||||
|
public class SessionAutoConfiguration {
|
||||||
|
|
||||||
|
@ConditionalOnClass(RedisConnectionFactory.class)
|
||||||
|
@ConditionalOnWebApplication
|
||||||
|
@ConditionalOnMissingBean(RedisHttpSessionConfiguration.class)
|
||||||
|
@EnableRedisHttpSession
|
||||||
|
@Configuration
|
||||||
|
public static class SessionRedisHttpConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ServerProperties serverProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisOperationsSessionRepository sessionRepository;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void applyConfigurationProperties() {
|
||||||
|
if (this.serverProperties.getSessionTimeout() != null) {
|
||||||
|
this.sessionRepository
|
||||||
|
.setDefaultMaxInactiveInterval(this.serverProperties
|
||||||
|
.getSessionTimeout());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
|
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
|
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
||||||
|
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
|
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
|
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
|
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
|
||||||
|
|
|
@ -135,6 +135,7 @@
|
||||||
<spring-security.version>4.0.1.RELEASE</spring-security.version>
|
<spring-security.version>4.0.1.RELEASE</spring-security.version>
|
||||||
<spring-security-jwt.version>1.0.3.RELEASE</spring-security-jwt.version>
|
<spring-security-jwt.version>1.0.3.RELEASE</spring-security-jwt.version>
|
||||||
<spring-security-oauth.version>2.0.7.RELEASE</spring-security-oauth.version>
|
<spring-security-oauth.version>2.0.7.RELEASE</spring-security-oauth.version>
|
||||||
|
<spring-session.version>1.0.1.RELEASE</spring-session.version>
|
||||||
<spring-social.version>1.1.2.RELEASE</spring-social.version>
|
<spring-social.version>1.1.2.RELEASE</spring-social.version>
|
||||||
<spring-social-facebook.version>2.0.1.RELEASE</spring-social-facebook.version>
|
<spring-social-facebook.version>2.0.1.RELEASE</spring-social-facebook.version>
|
||||||
<spring-social-linkedin.version>1.0.1.RELEASE</spring-social-linkedin.version>
|
<spring-social-linkedin.version>1.0.1.RELEASE</spring-social-linkedin.version>
|
||||||
|
@ -1695,6 +1696,11 @@
|
||||||
<artifactId>spring-security-oauth2</artifactId>
|
<artifactId>spring-security-oauth2</artifactId>
|
||||||
<version>${spring-security-oauth.version}</version>
|
<version>${spring-security-oauth.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.session</groupId>
|
||||||
|
<artifactId>spring-session</artifactId>
|
||||||
|
<version>${spring-session.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.social</groupId>
|
<groupId>org.springframework.social</groupId>
|
||||||
<artifactId>spring-social-config</artifactId>
|
<artifactId>spring-social-config</artifactId>
|
||||||
|
|
|
@ -2812,6 +2812,16 @@ class for more details.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[boot-features-session]]
|
||||||
|
== Spring Session
|
||||||
|
Spring Session provides support for managing a user's session information. If you are
|
||||||
|
writing a web application and Spring Session and Spring Data Redis are both on the
|
||||||
|
classpath, Spring Boot will auto-configure Spring Session through its
|
||||||
|
`@EnableRedisHttpSession`. Session data will be stored in Redis and the session timeout
|
||||||
|
can be configured using the `server.session-timeout` property.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[boot-features-jmx]]
|
[[boot-features-jmx]]
|
||||||
== Monitoring and management over JMX
|
== Monitoring and management over JMX
|
||||||
Java Management Extensions (JMX) provide a standard mechanism to monitor and manage
|
Java Management Extensions (JMX) provide a standard mechanism to monitor and manage
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
<module>spring-boot-sample-secure</module>
|
<module>spring-boot-sample-secure</module>
|
||||||
<module>spring-boot-sample-secure-oauth2</module>
|
<module>spring-boot-sample-secure-oauth2</module>
|
||||||
<module>spring-boot-sample-servlet</module>
|
<module>spring-boot-sample-servlet</module>
|
||||||
|
<module>spring-boot-sample-session-redis</module>
|
||||||
<module>spring-boot-sample-simple</module>
|
<module>spring-boot-sample-simple</module>
|
||||||
<module>spring-boot-sample-testng</module>
|
<module>spring-boot-sample-testng</module>
|
||||||
<module>spring-boot-sample-tomcat</module>
|
<module>spring-boot-sample-tomcat</module>
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-samples</artifactId>
|
||||||
|
<version>1.3.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-boot-sample-session-redis</artifactId>
|
||||||
|
<name>Spring Boot Session Redis Sample</name>
|
||||||
|
<description>Spring Boot Session Redis Sample</description>
|
||||||
|
<url>http://projects.spring.io/spring-boot/</url>
|
||||||
|
<organization>
|
||||||
|
<name>Pivotal Software, Inc.</name>
|
||||||
|
<url>http://www.spring.io</url>
|
||||||
|
</organization>
|
||||||
|
<properties>
|
||||||
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.session</groupId>
|
||||||
|
<artifactId>spring-session</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2015 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.session.redis;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SampleSessionRedisApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
SpringApplication.run(SampleSessionRedisApplication.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
static class HelloRestController {
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
String uid(HttpSession session) {
|
||||||
|
UUID uid = (UUID) session.getAttribute("uid");
|
||||||
|
if (uid == null) {
|
||||||
|
uid = UUID.randomUUID();
|
||||||
|
}
|
||||||
|
session.setAttribute("uid", uid);
|
||||||
|
return uid.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
server.session-timeout: 5
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2015 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.session.redis;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.RequestEntity;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link SampleSessionRedisApplication}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class SampleSessionRedisApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sessionExpiry() throws Exception {
|
||||||
|
|
||||||
|
String port = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ConfigurableApplicationContext context = new SpringApplicationBuilder()
|
||||||
|
.sources(SampleSessionRedisApplication.class)
|
||||||
|
.properties("server.port:0")
|
||||||
|
.initializers(new ServerPortInfoApplicationContextInitializer())
|
||||||
|
.run();
|
||||||
|
port = context.getEnvironment().getProperty("local.server.port");
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex) {
|
||||||
|
if (!redisServerRunning(ex)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uri = URI.create("http://localhost:" + port + "/");
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
|
||||||
|
String uuid1 = response.getBody();
|
||||||
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
requestHeaders.set("Cookie", response.getHeaders().getFirst("Set-Cookie"));
|
||||||
|
|
||||||
|
RequestEntity<Void> request = new RequestEntity<Void>(requestHeaders,
|
||||||
|
HttpMethod.GET, uri);
|
||||||
|
|
||||||
|
String uuid2 = restTemplate.exchange(request, String.class).getBody();
|
||||||
|
assertThat(uuid1, is(equalTo(uuid2)));
|
||||||
|
|
||||||
|
Thread.sleep(5000);
|
||||||
|
|
||||||
|
String uuid3 = restTemplate.exchange(request, String.class).getBody();
|
||||||
|
assertThat(uuid2, is(not(equalTo(uuid3))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean redisServerRunning(Throwable ex) {
|
||||||
|
if (ex instanceof RedisConnectionFailureException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (ex.getCause() == null || redisServerRunning(ex.getCause()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue