parent
ed9cd478ba
commit
57359058dd
|
@ -0,0 +1,7 @@
|
|||
= Reactive Applications
|
||||
|
||||
include::webflux.adoc[leveloffset=+1]
|
||||
|
||||
include::method.adoc[leveloffset=+1]
|
||||
|
||||
include::webtestclient.adoc[leveloffset=+1]
|
|
@ -0,0 +1,103 @@
|
|||
[[jc-erms]]
|
||||
= EnableReactiveMethodSecurity
|
||||
|
||||
Spring Security supports method security using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] which is setup using `ReactiveSecurityContextHolder`.
|
||||
For example, this demonstrates how to retrieve the currently logged in user's message.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
For this to work the return type of the method must be a `org.reactivestreams.Publisher` (i.e. `Mono`/`Flux`).
|
||||
This is necessary to integrate with Reactor's `Context`.
|
||||
====
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
|
||||
Mono<String> messageByUsername = ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.map(Authentication::getName)
|
||||
.flatMap(this::findMessageByUsername)
|
||||
// In a WebFlux application the `subscriberContext` is automatically setup using `ReactorContextWebFilter`
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
|
||||
|
||||
StepVerifier.create(messageByUsername)
|
||||
.expectNext("Hi user")
|
||||
.verifyComplete();
|
||||
----
|
||||
|
||||
with `this::findMessageByUsername` defined as:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Mono<String> findMessageByUsername(String username) {
|
||||
return Mono.just("Hi " + username);
|
||||
}
|
||||
----
|
||||
|
||||
Below is a minimal method security configuration when using method security in reactive applications.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@EnableReactiveMethodSecurity
|
||||
public class SecurityConfig {
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
|
||||
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
|
||||
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER","ADMIN").build();
|
||||
return new MapReactiveUserDetailsService(rob, admin);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Consider the following class:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class HelloWorldMessageService {
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public Mono<String> findMessage() {
|
||||
return Mono.just("Hello World!");
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Combined with our configuration above, `@PreAuthorize("hasRole('ADMIN')")` will ensure that `findByMessage` is only invoked by a user with the role `ADMIN`.
|
||||
It is important to note that any of the expressions in standard method security work for `@EnableReactiveMethodSecurity`.
|
||||
However, at this time we only support return type of `Boolean` or `boolean` of the expression.
|
||||
This means that the expression must not block.
|
||||
|
||||
When integrating with <<jc-webflux>>, the Reactor Context is automatically established by Spring Security according to the authenticated user.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@EnableWebFluxSecurity
|
||||
@EnableReactiveMethodSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
|
||||
return http
|
||||
// Demonstrate that method security works
|
||||
// Best practice to use both for defense in depth
|
||||
.authorizeExchange()
|
||||
.anyExchange().permitAll()
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MapReactiveUserDetailsService userDetailsService() {
|
||||
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
|
||||
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
|
||||
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER","ADMIN").build();
|
||||
return new MapReactiveUserDetailsService(rob, admin);
|
||||
}
|
||||
}
|
||||
|
||||
----
|
||||
|
||||
You can find a complete sample in {gh-samples-url}/javaconfig/hellowebflux-method[hellowebflux-method]
|
|
@ -0,0 +1,68 @@
|
|||
[[jc-webflux]]
|
||||
= WebFlux Security
|
||||
|
||||
Spring Security's WebFlux support relies on a `WebFilter` and works the same for Spring WebFlux and Spring WebFlux.Fn.
|
||||
You can find a few sample applications that demonstrate the code below:
|
||||
|
||||
* Hello WebFlux {gh-samples-url}/javaconfig/hellowebflux[hellowebflux]
|
||||
* Hello WebFlux.Fn {gh-samples-url}/javaconfig/hellowebfluxfn[hellowebfluxfn]
|
||||
* Hello WebFlux Method {gh-samples-url}/javaconfig/hellowebflux-method[hellowebflux-method]
|
||||
|
||||
|
||||
== Minimal WebFlux Security Configuration
|
||||
|
||||
You can find a minimal WebFlux Security configuration below:
|
||||
|
||||
[source,java]
|
||||
-----
|
||||
@EnableWebFluxSecurity
|
||||
public class HelloWebfluxSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
UserDetails user = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("user")
|
||||
.roles("USER")
|
||||
.build();
|
||||
return new MapReactiveUserDetailsService(user);
|
||||
}
|
||||
}
|
||||
-----
|
||||
|
||||
This configuration provides form and http basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default log in page and a default log out page, sets up security related HTTP headers, CSRF protection, and more.
|
||||
|
||||
== Explicit WebFlux Security Configuration
|
||||
|
||||
You can find an explicit version of the minimal WebFlux Security configuration below:
|
||||
|
||||
[source,java]
|
||||
-----
|
||||
@EnableWebFluxSecurity
|
||||
public class HelloWebfluxSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
UserDetails user = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("user")
|
||||
.roles("USER")
|
||||
.build();
|
||||
return new MapReactiveUserDetailsService(user);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
http
|
||||
.authorizeExchange()
|
||||
.anyExchange().authenticated()
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.formLogin();
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
-----
|
||||
|
||||
This configuration explicitly sets up all the same things as our minimal configuration.
|
||||
From here you can easily make the changes to the defaults.
|
|
@ -1,8 +1,8 @@
|
|||
[[test-webflux]]
|
||||
== WebFlux Support
|
||||
= WebFlux Support
|
||||
|
||||
[[test-erms]]
|
||||
=== Reactive Method Security
|
||||
== Reactive Method Security
|
||||
|
||||
For example, we can test our example from <<jc-erms>> using the same setup and annotations we did in <<test-method>>.
|
||||
Here is a minimal sample of what we can do:
|
||||
|
@ -41,7 +41,7 @@ public class HelloWorldMessageServiceTests {
|
|||
----
|
||||
|
||||
[[test-webtestclient]]
|
||||
=== WebTestClientSupport
|
||||
== WebTestClientSupport
|
||||
|
||||
Spring Security provides integration with `WebTestClient`.
|
||||
The basic setup looks like this:
|
||||
|
@ -70,7 +70,7 @@ public class HelloWebfluxMethodApplicationTests {
|
|||
}
|
||||
----
|
||||
|
||||
==== Authentication
|
||||
=== Authentication
|
||||
|
||||
After applying the Spring Security support to `WebTestClient` we can use either annotations or `mutateWith` support.
|
||||
For example:
|
||||
|
@ -134,7 +134,7 @@ public void messageWhenMutateWithMockAdminThenOk() throws Exception {
|
|||
----
|
||||
|
||||
|
||||
==== CSRF Support
|
||||
=== CSRF Support
|
||||
|
||||
Spring Security also provides support for CSRF testing with `WebTestClient`.
|
||||
For example:
|
|
@ -0,0 +1,17 @@
|
|||
= Servlet Applications
|
||||
|
||||
include::preface/index.adoc[leveloffset=+1]
|
||||
|
||||
include::architecture/index.adoc[leveloffset=+1]
|
||||
|
||||
include::test/index.adoc[leveloffset=+1]
|
||||
|
||||
include::web/index.adoc[leveloffset=+1]
|
||||
|
||||
include::authorization/index.adoc[leveloffset=+1]
|
||||
|
||||
include::additional-topics/index.adoc[leveloffset=+1]
|
||||
|
||||
include::data/index.adoc[leveloffset=+1]
|
||||
|
||||
include::appendix/index.adoc[leveloffset=+1]
|
|
@ -383,74 +383,6 @@ If not configured a status code 200 will be returned by default.
|
|||
- Section <<cas-singlelogout, Single Logout>> (CAS protocol)
|
||||
- Documentation for the <<nsa-logout, logout element>> in the Spring Security XML Namespace section
|
||||
|
||||
[[jc-webflux]]
|
||||
=== WebFlux Security
|
||||
|
||||
Spring Security's WebFlux support relies on a `WebFilter` and works the same for Spring WebFlux and Spring WebFlux.Fn.
|
||||
You can find a few sample applications that demonstrate the code below:
|
||||
|
||||
* Hello WebFlux {gh-samples-url}/javaconfig/hellowebflux[hellowebflux]
|
||||
* Hello WebFlux.Fn {gh-samples-url}/javaconfig/hellowebfluxfn[hellowebfluxfn]
|
||||
* Hello WebFlux Method {gh-samples-url}/javaconfig/hellowebflux-method[hellowebflux-method]
|
||||
|
||||
|
||||
==== Minimal WebFlux Security Configuration
|
||||
|
||||
You can find a minimal WebFlux Security configuration below:
|
||||
|
||||
[source,java]
|
||||
-----
|
||||
@EnableWebFluxSecurity
|
||||
public class HelloWebfluxSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
UserDetails user = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("user")
|
||||
.roles("USER")
|
||||
.build();
|
||||
return new MapReactiveUserDetailsService(user);
|
||||
}
|
||||
}
|
||||
-----
|
||||
|
||||
This configuration provides form and http basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default log in page and a default log out page, sets up security related HTTP headers, CSRF protection, and more.
|
||||
|
||||
==== Explicit WebFlux Security Configuration
|
||||
|
||||
You can find an explicit version of the minimal WebFlux Security configuration below:
|
||||
|
||||
[source,java]
|
||||
-----
|
||||
@EnableWebFluxSecurity
|
||||
public class HelloWebfluxSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
UserDetails user = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("user")
|
||||
.roles("USER")
|
||||
.build();
|
||||
return new MapReactiveUserDetailsService(user);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
http
|
||||
.authorizeExchange()
|
||||
.anyExchange().authenticated()
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.formLogin();
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
-----
|
||||
|
||||
This configuration explicitly sets up all the same things as our minimal configuration.
|
||||
From here you can easily make the changes to the defaults.
|
||||
|
||||
[[jc-oauth2login]]
|
||||
=== OAuth 2.0 Login
|
||||
|
@ -1302,110 +1234,6 @@ public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
|
|||
|
||||
For additional information about methods that can be overridden, refer to the `GlobalMethodSecurityConfiguration` Javadoc.
|
||||
|
||||
[[jc-erms]]
|
||||
==== EnableReactiveMethodSecurity
|
||||
|
||||
Spring Security supports method security using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] which is setup using `ReactiveSecurityContextHolder`.
|
||||
For example, this demonstrates how to retrieve the currently logged in user's message.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
For this to work the return type of the method must be a `org.reactivestreams.Publisher` (i.e. `Mono`/`Flux`).
|
||||
This is necessary to integrate with Reactor's `Context`.
|
||||
====
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
|
||||
Mono<String> messageByUsername = ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.map(Authentication::getName)
|
||||
.flatMap(this::findMessageByUsername)
|
||||
// In a WebFlux application the `subscriberContext` is automatically setup using `ReactorContextWebFilter`
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
|
||||
|
||||
StepVerifier.create(messageByUsername)
|
||||
.expectNext("Hi user")
|
||||
.verifyComplete();
|
||||
----
|
||||
|
||||
with `this::findMessageByUsername` defined as:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Mono<String> findMessageByUsername(String username) {
|
||||
return Mono.just("Hi " + username);
|
||||
}
|
||||
----
|
||||
|
||||
Below is a minimal method security configuration when using method security in reactive applications.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@EnableReactiveMethodSecurity
|
||||
public class SecurityConfig {
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
|
||||
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
|
||||
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER","ADMIN").build();
|
||||
return new MapReactiveUserDetailsService(rob, admin);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Consider the following class:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class HelloWorldMessageService {
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public Mono<String> findMessage() {
|
||||
return Mono.just("Hello World!");
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Combined with our configuration above, `@PreAuthorize("hasRole('ADMIN')")` will ensure that `findByMessage` is only invoked by a user with the role `ADMIN`.
|
||||
It is important to note that any of the expressions in standard method security work for `@EnableReactiveMethodSecurity`.
|
||||
However, at this time we only support return type of `Boolean` or `boolean` of the expression.
|
||||
This means that the expression must not block.
|
||||
|
||||
When integrating with <<jc-webflux>>, the Reactor Context is automatically established by Spring Security according to the authenticated user.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@EnableWebFluxSecurity
|
||||
@EnableReactiveMethodSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
|
||||
return http
|
||||
// Demonstrate that method security works
|
||||
// Best practice to use both for defense in depth
|
||||
.authorizeExchange()
|
||||
.anyExchange().permitAll()
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MapReactiveUserDetailsService userDetailsService() {
|
||||
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
|
||||
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
|
||||
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER","ADMIN").build();
|
||||
return new MapReactiveUserDetailsService(rob, admin);
|
||||
}
|
||||
}
|
||||
|
||||
----
|
||||
|
||||
You can find a complete sample in {gh-samples-url}/javaconfig/hellowebflux-method[hellowebflux-method]
|
||||
|
||||
=== Post Processing Configured Objects
|
||||
|
||||
Spring Security's Java Configuration does not expose every property of every object that it configures.
|
|
@ -2,24 +2,15 @@
|
|||
Ben Alex; Luke Taylor; Rob Winch; Gunnar Hillert; Joe Grandja; Jay Bryant
|
||||
:include-dir: _includes
|
||||
:security-api-url: http://docs.spring.io/spring-security/site/docs/current/apidocs/
|
||||
:source-indent: 0
|
||||
:tabsize: 2
|
||||
|
||||
Spring Security is a powerful and highly customizable authentication and access-control framework.
|
||||
It is the de-facto standard for securing Spring-based applications.
|
||||
|
||||
include::{include-dir}/preface/index.adoc[]
|
||||
|
||||
include::{include-dir}/architecture/index.adoc[]
|
||||
include::{include-dir}/servlet/index.adoc[]
|
||||
|
||||
include::{include-dir}/test/index.adoc[]
|
||||
|
||||
include::{include-dir}/web/index.adoc[]
|
||||
|
||||
include::{include-dir}/authorization/index.adoc[]
|
||||
|
||||
include::{include-dir}/additional-topics/index.adoc[]
|
||||
|
||||
include::{include-dir}/data/index.adoc[]
|
||||
|
||||
include::{include-dir}/appendix/index.adoc[]
|
||||
include::{include-dir}/reactive/index.adoc[]
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue