|
@@ -16,9 +16,8 @@
|
|
|
|
|
|
package org.springframework.security.config.annotation.web.reactive;
|
|
package org.springframework.security.config.annotation.web.reactive;
|
|
|
|
|
|
|
|
+import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.Test;
|
|
-import org.junit.experimental.runners.Enclosed;
|
|
|
|
-import org.junit.runner.RunWith;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.core.Ordered;
|
|
import org.springframework.core.Ordered;
|
|
@@ -26,18 +25,18 @@ import org.springframework.core.annotation.Order;
|
|
import org.springframework.core.io.buffer.DataBuffer;
|
|
import org.springframework.core.io.buffer.DataBuffer;
|
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
|
|
|
+import org.springframework.security.config.test.SpringTestRule;
|
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
|
import org.springframework.security.core.Authentication;
|
|
import org.springframework.security.core.Authentication;
|
|
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
|
|
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
|
|
-import org.springframework.security.core.userdetails.User;
|
|
|
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
|
|
|
+import org.springframework.security.core.userdetails.User;
|
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
|
|
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
|
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
|
import org.springframework.security.web.server.WebFilterChainProxy;
|
|
import org.springframework.security.web.server.WebFilterChainProxy;
|
|
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
|
|
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
|
|
-import org.springframework.test.context.junit4.SpringRunner;
|
|
|
|
import org.springframework.test.web.reactive.server.FluxExchangeResult;
|
|
import org.springframework.test.web.reactive.server.FluxExchangeResult;
|
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
|
import org.springframework.util.LinkedMultiValueMap;
|
|
import org.springframework.util.LinkedMultiValueMap;
|
|
@@ -56,228 +55,202 @@ import static org.springframework.web.reactive.function.client.ExchangeFilterFun
|
|
* @author Rob Winch
|
|
* @author Rob Winch
|
|
* @since 5.0
|
|
* @since 5.0
|
|
*/
|
|
*/
|
|
-@RunWith(Enclosed.class)
|
|
|
|
public class EnableWebFluxSecurityTests {
|
|
public class EnableWebFluxSecurityTests {
|
|
- @RunWith(SpringRunner.class)
|
|
|
|
- public static class Defaults {
|
|
|
|
- @Autowired WebFilterChainProxy springSecurityFilterChain;
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void defaultRequiresAuthentication() {
|
|
|
|
- WebTestClient client = WebTestClientBuilder
|
|
|
|
- .bindToWebFilters(this.springSecurityFilterChain)
|
|
|
|
- .build();
|
|
|
|
-
|
|
|
|
- client.get()
|
|
|
|
- .uri("/")
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().isUnauthorized()
|
|
|
|
- .expectBody().isEmpty();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void authenticateWhenBasicThenNoSession() {
|
|
|
|
- WebTestClient client = WebTestClientBuilder
|
|
|
|
- .bindToWebFilters(this.springSecurityFilterChain)
|
|
|
|
- .filter(basicAuthentication())
|
|
|
|
- .build();
|
|
|
|
-
|
|
|
|
- FluxExchangeResult<String> result = client.get()
|
|
|
|
- .attributes(basicAuthenticationCredentials("user", "password")).exchange()
|
|
|
|
- .expectStatus()
|
|
|
|
- .isOk()
|
|
|
|
- .returnResult(String.class);
|
|
|
|
- result.assertWithDiagnostics(() -> assertThat(result.getResponseCookies().isEmpty()));
|
|
|
|
- }
|
|
|
|
|
|
+ @Rule
|
|
|
|
+ public final SpringTestRule spring = new SpringTestRule();
|
|
|
|
|
|
- @Test
|
|
|
|
- public void defaultPopulatesReactorContext() {
|
|
|
|
- Principal currentPrincipal = new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
|
|
|
- WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
- (exchange, chain) ->
|
|
|
|
- chain.filter(exchange.mutate().principal(Mono.just(currentPrincipal)).build()),
|
|
|
|
- this.springSecurityFilterChain,
|
|
|
|
- (exchange,chain) ->
|
|
|
|
- Mono.subscriberContext()
|
|
|
|
- .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
- .flatMap( principal -> exchange.getResponse()
|
|
|
|
- .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
- ).build();
|
|
|
|
|
|
+ @Autowired
|
|
|
|
+ WebFilterChainProxy springSecurityFilterChain;
|
|
|
|
|
|
- client
|
|
|
|
- .get()
|
|
|
|
- .uri("/")
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().isOk()
|
|
|
|
- .expectBody(String.class).consumeWith( result -> assertThat(result.getResponseBody()).isEqualTo(currentPrincipal.getName()));
|
|
|
|
- }
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void defaultRequiresAuthentication() {
|
|
|
|
+ this.spring.register(Config.class).autowire();
|
|
|
|
|
|
- @Test
|
|
|
|
- public void defaultPopulatesReactorContextWhenAuthenticating() {
|
|
|
|
- WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
- this.springSecurityFilterChain,
|
|
|
|
- (exchange,chain) ->
|
|
|
|
- Mono.subscriberContext()
|
|
|
|
- .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
- .flatMap( principal -> exchange.getResponse()
|
|
|
|
- .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
- )
|
|
|
|
- .filter(basicAuthentication())
|
|
|
|
|
|
+ WebTestClient client = WebTestClientBuilder
|
|
|
|
+ .bindToWebFilters(this.springSecurityFilterChain)
|
|
.build();
|
|
.build();
|
|
|
|
|
|
- client
|
|
|
|
- .get()
|
|
|
|
- .uri("/")
|
|
|
|
- .attributes(basicAuthenticationCredentials("user","password"))
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().isOk()
|
|
|
|
- .expectBody(String.class).consumeWith( result -> assertThat(result.getResponseBody()).isEqualTo("user"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @EnableWebFluxSecurity
|
|
|
|
- static class Config {
|
|
|
|
- @Bean
|
|
|
|
- public ReactiveUserDetailsService userDetailsRepository() {
|
|
|
|
- return new MapReactiveUserDetailsService(User.withUsername("user")
|
|
|
|
- .password("password")
|
|
|
|
- .roles("USER")
|
|
|
|
- .build()
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ client.get()
|
|
|
|
+ .uri("/")
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().isUnauthorized()
|
|
|
|
+ .expectBody().isEmpty();
|
|
}
|
|
}
|
|
|
|
|
|
- @RunWith(SpringRunner.class)
|
|
|
|
- public static class CustomPasswordEncoder {
|
|
|
|
- @Autowired WebFilterChainProxy springSecurityFilterChain;
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void authenticateWhenBasicThenNoSession() {
|
|
|
|
+ this.spring.register(Config.class).autowire();
|
|
|
|
|
|
- @Test
|
|
|
|
- public void passwordEncoderBeanIsUsed() {
|
|
|
|
- WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
- this.springSecurityFilterChain,
|
|
|
|
- (exchange,chain) ->
|
|
|
|
- Mono.subscriberContext()
|
|
|
|
- .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
- .flatMap( principal -> exchange.getResponse()
|
|
|
|
- .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
- )
|
|
|
|
|
|
+ WebTestClient client = WebTestClientBuilder
|
|
|
|
+ .bindToWebFilters(this.springSecurityFilterChain)
|
|
.filter(basicAuthentication())
|
|
.filter(basicAuthentication())
|
|
.build();
|
|
.build();
|
|
|
|
|
|
- client
|
|
|
|
- .get()
|
|
|
|
- .uri("/")
|
|
|
|
- .attributes(basicAuthenticationCredentials("user","password"))
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().isOk()
|
|
|
|
- .expectBody(String.class).consumeWith( result -> assertThat(result.getResponseBody()).isEqualTo("user"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @EnableWebFluxSecurity
|
|
|
|
- static class Config {
|
|
|
|
- @Bean
|
|
|
|
- public ReactiveUserDetailsService userDetailsRepository(PasswordEncoder encoder) {
|
|
|
|
- return new MapReactiveUserDetailsService(User.withUsername("user")
|
|
|
|
- .password(encoder.encode("password"))
|
|
|
|
- .roles("USER")
|
|
|
|
- .build()
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ FluxExchangeResult<String> result = client.get()
|
|
|
|
+ .attributes(basicAuthenticationCredentials("user", "password")).exchange()
|
|
|
|
+ .expectStatus()
|
|
|
|
+ .isOk()
|
|
|
|
+ .returnResult(String.class);
|
|
|
|
+ result.assertWithDiagnostics(() -> assertThat(result.getResponseCookies().isEmpty()));
|
|
|
|
+ }
|
|
|
|
|
|
- @Bean
|
|
|
|
- public static PasswordEncoder passwordEncoder() {
|
|
|
|
- return new BCryptPasswordEncoder();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void defaultPopulatesReactorContext() {
|
|
|
|
+ this.spring.register(Config.class).autowire();
|
|
|
|
+ Principal currentPrincipal = new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
|
|
|
+ WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
+ (exchange, chain) ->
|
|
|
|
+ chain.filter(exchange.mutate().principal(Mono.just(currentPrincipal)).build()),
|
|
|
|
+ this.springSecurityFilterChain,
|
|
|
|
+ (exchange,chain) ->
|
|
|
|
+ Mono.subscriberContext()
|
|
|
|
+ .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
+ .flatMap( principal -> exchange.getResponse()
|
|
|
|
+ .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
+ ).build();
|
|
|
|
+
|
|
|
|
+ client
|
|
|
|
+ .get()
|
|
|
|
+ .uri("/")
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().isOk()
|
|
|
|
+ .expectBody(String.class).consumeWith( result -> assertThat(result.getResponseBody()).isEqualTo(currentPrincipal.getName()));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void defaultPopulatesReactorContextWhenAuthenticating() {
|
|
|
|
+ this.spring.register(Config.class).autowire();
|
|
|
|
+ WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
+ this.springSecurityFilterChain,
|
|
|
|
+ (exchange,chain) ->
|
|
|
|
+ Mono.subscriberContext()
|
|
|
|
+ .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
+ .flatMap( principal -> exchange.getResponse()
|
|
|
|
+ .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
+ )
|
|
|
|
+ .filter(basicAuthentication())
|
|
|
|
+ .build();
|
|
|
|
+
|
|
|
|
+ client
|
|
|
|
+ .get()
|
|
|
|
+ .uri("/")
|
|
|
|
+ .attributes(basicAuthenticationCredentials("user","password"))
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().isOk()
|
|
|
|
+ .expectBody(String.class).consumeWith( result -> assertThat(result.getResponseBody()).isEqualTo("user"));
|
|
|
|
+ }
|
|
|
|
|
|
- @RunWith(SpringRunner.class)
|
|
|
|
- public static class FormLoginTests {
|
|
|
|
- @Autowired WebFilterChainProxy springSecurityFilterChain;
|
|
|
|
- @Test
|
|
|
|
- public void formLoginWorks() {
|
|
|
|
- WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
- this.springSecurityFilterChain,
|
|
|
|
- (exchange,chain) ->
|
|
|
|
- Mono.subscriberContext()
|
|
|
|
- .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
- .flatMap( principal -> exchange.getResponse()
|
|
|
|
- .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
- )
|
|
|
|
- .build();
|
|
|
|
|
|
+ @EnableWebFluxSecurity
|
|
|
|
+ static class Config {
|
|
|
|
+ @Bean
|
|
|
|
+ public ReactiveUserDetailsService userDetailsRepository() {
|
|
|
|
+ return new MapReactiveUserDetailsService(User.withUsername("user")
|
|
|
|
+ .password("password")
|
|
|
|
+ .roles("USER")
|
|
|
|
+ .build()
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void passwordEncoderBeanIsUsed() {
|
|
|
|
+ this.spring.register(CustomPasswordEncoderConfig.class).autowire();
|
|
|
|
+ WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
+ this.springSecurityFilterChain,
|
|
|
|
+ (exchange,chain) ->
|
|
|
|
+ Mono.subscriberContext()
|
|
|
|
+ .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
+ .flatMap( principal -> exchange.getResponse()
|
|
|
|
+ .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
+ )
|
|
|
|
+ .filter(basicAuthentication())
|
|
|
|
+ .build();
|
|
|
|
+
|
|
|
|
+ client
|
|
|
|
+ .get()
|
|
|
|
+ .uri("/")
|
|
|
|
+ .attributes(basicAuthenticationCredentials("user","password"))
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().isOk()
|
|
|
|
+ .expectBody(String.class).consumeWith( result -> assertThat(result.getResponseBody()).isEqualTo("user"));
|
|
|
|
+ }
|
|
|
|
|
|
- MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
|
|
|
|
- data.add("username", "user");
|
|
|
|
- data.add("password", "password");
|
|
|
|
- client
|
|
|
|
- .post()
|
|
|
|
- .uri("/login")
|
|
|
|
- .body(BodyInserters.fromFormData(data))
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().is3xxRedirection()
|
|
|
|
- .expectHeader().valueMatches("Location", "/");
|
|
|
|
|
|
+ @EnableWebFluxSecurity
|
|
|
|
+ static class CustomPasswordEncoderConfig {
|
|
|
|
+ @Bean
|
|
|
|
+ public ReactiveUserDetailsService userDetailsRepository(PasswordEncoder encoder) {
|
|
|
|
+ return new MapReactiveUserDetailsService(User.withUsername("user")
|
|
|
|
+ .password(encoder.encode("password"))
|
|
|
|
+ .roles("USER")
|
|
|
|
+ .build()
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
|
|
- @EnableWebFluxSecurity
|
|
|
|
- static class Config {
|
|
|
|
- @Bean
|
|
|
|
- public ReactiveUserDetailsService userDetailsRepository() {
|
|
|
|
- return new MapReactiveUserDetailsService(User.withUsername("user")
|
|
|
|
- .password("password")
|
|
|
|
- .roles("USER")
|
|
|
|
- .build()
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ @Bean
|
|
|
|
+ public static PasswordEncoder passwordEncoder() {
|
|
|
|
+ return new BCryptPasswordEncoder();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- @RunWith(SpringRunner.class)
|
|
|
|
- public static class MultiServerHttpSecurity {
|
|
|
|
- @Autowired WebFilterChainProxy springSecurityFilterChain;
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void multiWorks() {
|
|
|
|
- WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void formLoginWorks() {
|
|
|
|
+ this.spring.register(Config.class).autowire();
|
|
|
|
+ WebTestClient client = WebTestClientBuilder.bindToWebFilters(
|
|
|
|
+ this.springSecurityFilterChain,
|
|
|
|
+ (exchange,chain) ->
|
|
|
|
+ Mono.subscriberContext()
|
|
|
|
+ .flatMap( c -> c.<Mono<Principal>>get(Authentication.class))
|
|
|
|
+ .flatMap( principal -> exchange.getResponse()
|
|
|
|
+ .writeWith(Mono.just(toDataBuffer(principal.getName()))))
|
|
|
|
+ )
|
|
|
|
+ .build();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
|
|
|
|
+ data.add("username", "user");
|
|
|
|
+ data.add("password", "password");
|
|
|
|
+ client
|
|
|
|
+ .post()
|
|
|
|
+ .uri("/login")
|
|
|
|
+ .body(BodyInserters.fromFormData(data))
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().is3xxRedirection()
|
|
|
|
+ .expectHeader().valueMatches("Location", "/");
|
|
|
|
+ }
|
|
|
|
|
|
- client.get()
|
|
|
|
- .uri("/api/test")
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().isUnauthorized()
|
|
|
|
- .expectBody().isEmpty();
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void multiWorks() {
|
|
|
|
+ this.spring.register(MultiSecurityHttpConfig.class).autowire();
|
|
|
|
+ WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
|
|
|
|
+
|
|
|
|
+ client.get()
|
|
|
|
+ .uri("/api/test")
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().isUnauthorized()
|
|
|
|
+ .expectBody().isEmpty();
|
|
|
|
+
|
|
|
|
+ client.get()
|
|
|
|
+ .uri("/test")
|
|
|
|
+ .exchange()
|
|
|
|
+ .expectStatus().isOk();
|
|
|
|
+ }
|
|
|
|
|
|
- client.get()
|
|
|
|
- .uri("/test")
|
|
|
|
- .exchange()
|
|
|
|
- .expectStatus().isOk();
|
|
|
|
|
|
+ @EnableWebFluxSecurity
|
|
|
|
+ static class MultiSecurityHttpConfig {
|
|
|
|
+ @Order(Ordered.HIGHEST_PRECEDENCE) @Bean public SecurityWebFilterChain apiHttpSecurity(
|
|
|
|
+ ServerHttpSecurity http) {
|
|
|
|
+ http.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**"))
|
|
|
|
+ .authorizeExchange().anyExchange().denyAll();
|
|
|
|
+ return http.build();
|
|
}
|
|
}
|
|
|
|
|
|
- @EnableWebFluxSecurity
|
|
|
|
- static class Config {
|
|
|
|
- @Order(Ordered.HIGHEST_PRECEDENCE)
|
|
|
|
- @Bean
|
|
|
|
- public SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) {
|
|
|
|
- http
|
|
|
|
- .securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**"))
|
|
|
|
- .authorizeExchange()
|
|
|
|
- .anyExchange().denyAll();
|
|
|
|
- return http.build();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Bean
|
|
|
|
- public SecurityWebFilterChain httpSecurity(ServerHttpSecurity http) {
|
|
|
|
- return http.build();
|
|
|
|
- }
|
|
|
|
|
|
+ @Bean public SecurityWebFilterChain httpSecurity(ServerHttpSecurity http) {
|
|
|
|
+ return http.build();
|
|
|
|
+ }
|
|
|
|
|
|
- @Bean
|
|
|
|
- public ReactiveUserDetailsService userDetailsRepository() {
|
|
|
|
- return new MapReactiveUserDetailsService(User.withUsername("user")
|
|
|
|
- .password("password")
|
|
|
|
- .roles("USER")
|
|
|
|
- .build()
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ @Bean public ReactiveUserDetailsService userDetailsRepository() {
|
|
|
|
+ return new MapReactiveUserDetailsService(
|
|
|
|
+ User.withUsername("user").password("password").roles("USER").build());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|