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>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<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.oauth2.OAuth2AutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
<spring-security.version>4.0.1.RELEASE</spring-security.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-session.version>1.0.1.RELEASE</spring-session.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-linkedin.version>1.0.1.RELEASE</spring-social-linkedin.version>
|
||||
|
@ -1695,6 +1696,11 @@
|
|||
<artifactId>spring-security-oauth2</artifactId>
|
||||
<version>${spring-security-oauth.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<version>${spring-session.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.social</groupId>
|
||||
<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]]
|
||||
== Monitoring and management over JMX
|
||||
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-oauth2</module>
|
||||
<module>spring-boot-sample-servlet</module>
|
||||
<module>spring-boot-sample-session-redis</module>
|
||||
<module>spring-boot-sample-simple</module>
|
||||
<module>spring-boot-sample-testng</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