diff --git a/2019-11/spring-24-SS-ACL/pom.xml b/2019-11/spring-24-SS-ACL/pom.xml
index 49358ba4..3dc8c0d2 100644
--- a/2019-11/spring-24-SS-ACL/pom.xml
+++ b/2019-11/spring-24-SS-ACL/pom.xml
@@ -5,7 +5,7 @@
4.0.0
ru.otus
- spring-framework-22-acl
+ spring-framework-24-acl
1.0-SNAPSHOT
diff --git a/2019-11/spring-24-WebFlux/pom.xml b/2019-11/spring-24-WebFlux/pom.xml
new file mode 100644
index 00000000..418cc62f
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-framework-24-webflux
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.5.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ org.springframework.security
+ spring-security-core
+
+
+ org.springframework.security
+ spring-security-config
+
+
+ org.springframework.security
+ spring-security-web
+
+
+ org.springframework.security
+ spring-security-webflux
+ 5.0.0.M5
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb-reactive
+
+
+
+ de.flapdoodle.embed
+ de.flapdoodle.embed.mongo
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+ spring-milestone
+ http://repo.spring.io/milestone
+
+
+
diff --git a/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..490b4b3a
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,22 @@
+package ru.otus.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class);
+ }
+
+ @Bean
+ RouterFunction staticResourceRouter() {
+ return RouterFunctions.resources("/**.html", new ClassPathResource("static/"));
+ }
+}
diff --git a/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/data/Person.java b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/data/Person.java
new file mode 100644
index 00000000..067c0b64
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/data/Person.java
@@ -0,0 +1,41 @@
+package ru.otus.spring.data;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document
+public class Person {
+
+ @Id
+ private String id;
+
+ private String name;
+
+ public Person() {
+ }
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public Person(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java
new file mode 100644
index 00000000..2f1994d3
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java
@@ -0,0 +1,11 @@
+package ru.otus.spring.data;
+
+import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
+import org.springframework.stereotype.Repository;
+import reactor.core.publisher.Mono;
+
+@Repository
+public interface PersonRepository extends ReactiveMongoRepository {
+
+ Mono findByName(String string);
+}
diff --git a/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java
new file mode 100644
index 00000000..f1d4333c
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java
@@ -0,0 +1,34 @@
+package ru.otus.spring.rest;
+
+import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import ru.otus.spring.data.Person;
+import ru.otus.spring.data.PersonRepository;
+
+@RestController
+public class PersonController {
+
+ private final PersonRepository personRepository;
+
+ public PersonController(PersonRepository personRepository) {
+ this.personRepository = personRepository;
+ }
+
+ @GetMapping("/person")
+ public Flux getAll() {
+ return personRepository.findAll();
+ }
+
+ @GetMapping("/person/find")
+ public Mono find(@RequestParam("name") String name) {
+ return personRepository.findByName(name)
+ .cache();
+ }
+
+
+ @PostMapping("/person")
+ public Mono savePerson(@RequestBody Person person) {
+ return personRepository.save(person);
+ }
+}
diff --git a/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
new file mode 100644
index 00000000..2ddf4e0e
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
@@ -0,0 +1,47 @@
+package ru.otus.spring.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+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.core.userdetails.UserDetails;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+
+@Configuration
+@EnableWebFluxSecurity
+public class SecurityConfiguration {
+
+ @Bean
+ public SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
+ return http
+ .authorizeExchange()
+ .pathMatchers(HttpMethod.GET, "/authenticated.html").hasRole("USER")
+ // anonymous
+ .anyExchange().permitAll()
+ .and()
+ .httpBasic()
+ .and()
+ .build();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return NoOpPasswordEncoder.getInstance();
+ }
+
+ @Bean
+ public ReactiveUserDetailsService userDetailsService() {
+ UserDetails user = User
+ .withUsername("user")
+ .password("password")
+ .roles("USER")
+ .build();
+ return new MapReactiveUserDetailsService(user);
+ }
+}
diff --git a/2019-11/spring-24-WebFlux/src/main/resources/static/authenticated.html b/2019-11/spring-24-WebFlux/src/main/resources/static/authenticated.html
new file mode 100644
index 00000000..e4756c01
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/resources/static/authenticated.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Только для аторизованных
+
+
diff --git a/2019-11/spring-24-WebFlux/src/main/resources/static/index.html b/2019-11/spring-24-WebFlux/src/main/resources/static/index.html
new file mode 100644
index 00000000..a89ba331
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/resources/static/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+/public.html
+
+/authenticated.html
+
+
diff --git a/2019-11/spring-24-WebFlux/src/main/resources/static/public.html b/2019-11/spring-24-WebFlux/src/main/resources/static/public.html
new file mode 100644
index 00000000..77188469
--- /dev/null
+++ b/2019-11/spring-24-WebFlux/src/main/resources/static/public.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Доступен всем
+
+