diff --git a/2022-11/spring-27/WebFlux/pom.xml b/2022-11/spring-27/WebFlux/pom.xml new file mode 100644 index 00000000..f6572b55 --- /dev/null +++ b/2022-11/spring-27/WebFlux/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + ru.otus + spring-framework-27-webflux + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.7.8 + + + + + 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.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/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/WebFluxStarter.java b/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/WebFluxStarter.java new file mode 100644 index 00000000..7a06898e --- /dev/null +++ b/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/WebFluxStarter.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 WebFluxStarter { + + public static void main( String[] args ) { + SpringApplication.run( WebFluxStarter.class ); + } + + @Bean + RouterFunction staticResourceRouter() { + return RouterFunctions.resources( "/**.html", new ClassPathResource( "static/" ) ); + } +} diff --git a/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/data/Person.java b/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/data/Person.java new file mode 100644 index 00000000..bedf08b0 --- /dev/null +++ b/2022-11/spring-27/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/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java b/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java new file mode 100644 index 00000000..8f5f3d67 --- /dev/null +++ b/2022-11/spring-27/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/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..7af4b0a9 --- /dev/null +++ b/2022-11/spring-27/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/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2022-11/spring-27/WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java new file mode 100644 index 00000000..545dd650 --- /dev/null +++ b/2022-11/spring-27/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.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; +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; + +@EnableWebFluxSecurity +@EnableReactiveMethodSecurity +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/2022-11/spring-27/WebFlux/src/main/resources/application.yml b/2022-11/spring-27/WebFlux/src/main/resources/application.yml new file mode 100644 index 00000000..e8d496cc --- /dev/null +++ b/2022-11/spring-27/WebFlux/src/main/resources/application.yml @@ -0,0 +1 @@ +spring.mongodb.embedded.version: 3.5.5 \ No newline at end of file diff --git a/2022-11/spring-27/WebFlux/src/main/resources/static/authenticated.html b/2022-11/spring-27/WebFlux/src/main/resources/static/authenticated.html new file mode 100644 index 00000000..9f8b0d7e --- /dev/null +++ b/2022-11/spring-27/WebFlux/src/main/resources/static/authenticated.html @@ -0,0 +1,9 @@ + + + + + + +Только для авторизованных + + diff --git a/2022-11/spring-27/WebFlux/src/main/resources/static/index.html b/2022-11/spring-27/WebFlux/src/main/resources/static/index.html new file mode 100644 index 00000000..a89ba331 --- /dev/null +++ b/2022-11/spring-27/WebFlux/src/main/resources/static/index.html @@ -0,0 +1,11 @@ + + + + + + +/public.html +
+/authenticated.html + + diff --git a/2022-11/spring-27/WebFlux/src/main/resources/static/public.html b/2022-11/spring-27/WebFlux/src/main/resources/static/public.html new file mode 100644 index 00000000..77188469 --- /dev/null +++ b/2022-11/spring-27/WebFlux/src/main/resources/static/public.html @@ -0,0 +1,9 @@ + + + + + + +Доступен всем + + diff --git a/2022-11/spring-27/oauth/pom.xml b/2022-11/spring-27/oauth/pom.xml new file mode 100644 index 00000000..36300726 --- /dev/null +++ b/2022-11/spring-27/oauth/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + ru.otus + spring-framework-27-oauth + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.6.10 + + + + 2.6.11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + + org.springdoc + springdoc-openapi-ui + 1.6.9 + + + + org.webjars + jquery + 3.4.1 + + + org.webjars + bootstrap + 4.3.1 + + + org.webjars + webjars-locator-core + + + org.webjars + js-cookie + 2.1.0 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/GithubApplication.java b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/GithubApplication.java new file mode 100644 index 00000000..7a69b021 --- /dev/null +++ b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/GithubApplication.java @@ -0,0 +1,13 @@ +package ru.otus.spring.sso; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GithubApplication { + + public static void main(String[] args) { + SpringApplication.run( GithubApplication.class, args); + } + +} \ No newline at end of file diff --git a/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/controller/IndexController.java b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/controller/IndexController.java new file mode 100644 index 00000000..a6e55cd2 --- /dev/null +++ b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/controller/IndexController.java @@ -0,0 +1,13 @@ +package ru.otus.spring.sso.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class IndexController { + + @GetMapping("/") + public String indexPage() { + return "index"; + } +} diff --git a/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/controller/UserController.java b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/controller/UserController.java new file mode 100644 index 00000000..a99dc54d --- /dev/null +++ b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/controller/UserController.java @@ -0,0 +1,17 @@ +package ru.otus.spring.sso.controller; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.Map; + +@RestController +public class UserController { + @GetMapping("/user") + public Map user( @AuthenticationPrincipal OAuth2User principal) { + return Collections.singletonMap("name", principal.getAttribute("name")); + } +} diff --git a/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/security/SecurityConfig.java b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/security/SecurityConfig.java new file mode 100644 index 00000000..f310baa1 --- /dev/null +++ b/2022-11/spring-27/oauth/src/main/java/ru/otus/spring/sso/security/SecurityConfig.java @@ -0,0 +1,28 @@ +package ru.otus.spring.sso.security; + +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; + +public class SecurityConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure( HttpSecurity http ) throws Exception { + // @formatter:off + http + .authorizeRequests( a -> a + .antMatchers( "/", "/error", "/webjars/**" ).permitAll() + .anyRequest().authenticated() + ) + .exceptionHandling( e -> e + .authenticationEntryPoint( new HttpStatusEntryPoint( HttpStatus.UNAUTHORIZED ) ) + ) + .csrf().disable() + .logout( l -> l + .logoutSuccessUrl( "/" ).permitAll() + ) + + .oauth2Login(); + // @formatter:on + } +} diff --git a/2022-11/spring-27/oauth/src/main/resources/application.yml b/2022-11/spring-27/oauth/src/main/resources/application.yml new file mode 100644 index 00000000..8ef3c0db --- /dev/null +++ b/2022-11/spring-27/oauth/src/main/resources/application.yml @@ -0,0 +1,13 @@ +spring: + security: + oauth2: + client: + registration: + github: + clientId: fdec09b924be7f214eaa + clientSecret: 5436beb72dc2ec7f2320afcab5185c1ea03d484b + +logging: + level: + root: error + org.springframework.security: DEBUG \ No newline at end of file diff --git a/2022-11/spring-27/oauth/src/main/resources/templates/index.html b/2022-11/spring-27/oauth/src/main/resources/templates/index.html new file mode 100644 index 00000000..09dae5ba --- /dev/null +++ b/2022-11/spring-27/oauth/src/main/resources/templates/index.html @@ -0,0 +1,18 @@ + + + + + + Demo + + + + + + + + +

Demo

+
+ + \ No newline at end of file