7 changed files with 279 additions and 0 deletions
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
= Spring Boot Spring Session Sample |
||||
|
||||
This sample demonstrates the Spring Session WebFlux auto-configuration support. Spring |
||||
Session supports multiple reactive session store types, including: |
||||
|
||||
* `Redis` |
||||
* `MongoDB` |
||||
|
||||
|
||||
|
||||
== Using a different session store |
||||
Initially, the project uses MongoDB session store backed by an embedded MongoDB. You can |
||||
try out your favorite session store as explained below. |
||||
|
||||
|
||||
|
||||
=== Redis |
||||
Add `org.springframework.session:spring-session-data-redis` and |
||||
`spring-boot-starter-data-redis-reactive` dependencies to the project and make sure it is |
||||
configured properly (by default, a Redis instance with the default settings is expected |
||||
on your local box). |
||||
|
||||
TIP: Run sample application using Redis session store using |
||||
`$mvn spring-boot:run -Predis`. |
||||
|
||||
|
||||
|
||||
=== MongoDB |
||||
Add `org.springframework.session:spring-session-data-mongodb` and |
||||
`spring-boot-starter-data-mongodb-reactive` and |
||||
`de.flapdoodle.embed:de.flapdoodle.embed.mongo` dependencies to the project. An embedded |
||||
MongoDB is automatically configured. |
||||
|
||||
TIP: Run sample application using MongoDB session store using |
||||
`$mvn spring-boot:run -Pmongodb`. |
||||
|
||||
Note that this profile is active by default. |
||||
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
<?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>${revision}</version> |
||||
</parent> |
||||
<artifactId>spring-boot-sample-session-webflux</artifactId> |
||||
<name>Spring Boot Session WebFlux Sample</name> |
||||
<description>Spring Boot Session WebFlux Sample</description> |
||||
<properties> |
||||
<main.basedir>${basedir}/../..</main.basedir> |
||||
</properties> |
||||
<dependencies> |
||||
<!-- Compile --> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-webflux</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-security</artifactId> |
||||
</dependency> |
||||
<!-- Test --> |
||||
<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> |
||||
<profiles> |
||||
<profile> |
||||
<id>redis</id> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.springframework.session</groupId> |
||||
<artifactId>spring-session-data-redis</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-data-redis-reactive</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
</profile> |
||||
<profile> |
||||
<id>mongodb</id> |
||||
<activation> |
||||
<activeByDefault>true</activeByDefault> |
||||
</activation> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.springframework.session</groupId> |
||||
<artifactId>spring-session-data-mongodb</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>de.flapdoodle.embed</groupId> |
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
</profile> |
||||
</profiles> |
||||
</project> |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
/* |
||||
* Copyright 2012-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 sample.session; |
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
import org.springframework.web.server.WebSession; |
||||
|
||||
@RestController |
||||
public class HelloRestController { |
||||
|
||||
@GetMapping("/") |
||||
String sessionId(WebSession session) { |
||||
return session.getId(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright 2012-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 sample.session; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.security.config.web.server.ServerHttpSecurity; |
||||
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; |
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService; |
||||
import org.springframework.security.core.userdetails.User; |
||||
import org.springframework.security.web.server.SecurityWebFilterChain; |
||||
import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; |
||||
|
||||
@SpringBootApplication |
||||
public class SampleSessionWebFluxApplication { |
||||
|
||||
public static void main(String[] args) { |
||||
SpringApplication.run(SampleSessionWebFluxApplication.class); |
||||
} |
||||
|
||||
@Bean |
||||
public ReactiveUserDetailsService userDetailsRepository() { |
||||
return new MapReactiveUserDetailsService(User.withDefaultPasswordEncoder() |
||||
.username("user").password("password").roles("USER").build()); |
||||
} |
||||
|
||||
@Bean |
||||
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
||||
// @formatter:off
|
||||
return http |
||||
.authorizeExchange() |
||||
.anyExchange().authenticated() |
||||
.and() |
||||
.httpBasic().securityContextRepository(new WebSessionServerSecurityContextRepository()) |
||||
.and() |
||||
.formLogin() |
||||
.and() |
||||
.build(); |
||||
// @formatter:on
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,77 @@
@@ -0,0 +1,77 @@
|
||||
/* |
||||
* Copyright 2012-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 sample.session; |
||||
|
||||
import java.util.Base64; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.web.server.LocalServerPort; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseCookie; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
import org.springframework.web.reactive.function.client.ClientResponse; |
||||
import org.springframework.web.reactive.function.client.WebClient; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Integration tests for {@link SampleSessionWebFluxApplication}. |
||||
* |
||||
* @author Vedran Pavic |
||||
*/ |
||||
@RunWith(SpringRunner.class) |
||||
@SpringBootTest(properties = "server.session.timeout:1", webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) |
||||
public class SampleSessionWebFluxApplicationTests { |
||||
|
||||
@LocalServerPort |
||||
private int port; |
||||
|
||||
@Autowired |
||||
private WebClient.Builder webClientBuilder; |
||||
|
||||
@Test |
||||
public void userDefinedMappingsSecureByDefault() throws Exception { |
||||
WebClient webClient = this.webClientBuilder |
||||
.baseUrl("http://localhost:" + this.port + "/").build(); |
||||
|
||||
ClientResponse response = webClient.get().header("Authorization", getBasicAuth()) |
||||
.exchange().block(); |
||||
assertThat(response.statusCode()).isEqualTo(HttpStatus.OK); |
||||
ResponseCookie sessionCookie = response.cookies().getFirst("SESSION"); |
||||
String sessionId = response.bodyToMono(String.class).block(); |
||||
|
||||
response = webClient.get().cookie("SESSION", sessionCookie.getValue()).exchange() |
||||
.block(); |
||||
assertThat(response.statusCode()).isEqualTo(HttpStatus.OK); |
||||
assertThat(response.bodyToMono(String.class).block()).isEqualTo(sessionId); |
||||
|
||||
Thread.sleep(1000); |
||||
|
||||
response = webClient.get().cookie("SESSION", sessionCookie.getValue()).exchange() |
||||
.block(); |
||||
assertThat(response.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); |
||||
} |
||||
|
||||
private String getBasicAuth() { |
||||
return "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes()); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue