228 lines
7.2 KiB
Plaintext
228 lines
7.2 KiB
Plaintext
[[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}/reactive/webflux/java/hello-security[hellowebflux]
|
|
* Hello WebFlux.Fn {gh-samples-url}/reactive/webflux-fn/hello-security[hellowebfluxfn]
|
|
* Hello WebFlux Method {gh-samples-url}/reactive/webflux/java/method[hellowebflux-method]
|
|
|
|
|
|
== Minimal WebFlux Security Configuration
|
|
|
|
You can find a minimal WebFlux Security configuration below:
|
|
|
|
.Minimal WebFlux Security Configuration
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
-----
|
|
|
|
@EnableWebFluxSecurity
|
|
public class HelloWebfluxSecurityConfig {
|
|
|
|
@Bean
|
|
public MapReactiveUserDetailsService userDetailsService() {
|
|
UserDetails user = User.withDefaultPasswordEncoder()
|
|
.username("user")
|
|
.password("user")
|
|
.roles("USER")
|
|
.build();
|
|
return new MapReactiveUserDetailsService(user);
|
|
}
|
|
}
|
|
-----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
-----
|
|
@EnableWebFluxSecurity
|
|
class HelloWebfluxSecurityConfig {
|
|
|
|
@Bean
|
|
fun userDetailsService(): ReactiveUserDetailsService {
|
|
val userDetails = User.withDefaultPasswordEncoder()
|
|
.username("user")
|
|
.password("user")
|
|
.roles("USER")
|
|
.build()
|
|
return MapReactiveUserDetailsService(userDetails)
|
|
}
|
|
}
|
|
-----
|
|
====
|
|
|
|
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:
|
|
|
|
.Explicit WebFlux Security Configuration
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
-----
|
|
@Configuration
|
|
@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(exchanges -> exchanges
|
|
.anyExchange().authenticated()
|
|
)
|
|
.httpBasic(withDefaults())
|
|
.formLogin(withDefaults());
|
|
return http.build();
|
|
}
|
|
}
|
|
-----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
-----
|
|
@Configuration
|
|
@EnableWebFluxSecurity
|
|
class HelloWebfluxSecurityConfig {
|
|
|
|
@Bean
|
|
fun userDetailsService(): ReactiveUserDetailsService {
|
|
val userDetails = User.withDefaultPasswordEncoder()
|
|
.username("user")
|
|
.password("user")
|
|
.roles("USER")
|
|
.build()
|
|
return MapReactiveUserDetailsService(userDetails)
|
|
}
|
|
|
|
@Bean
|
|
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
|
return http {
|
|
authorizeExchange {
|
|
authorize(anyExchange, authenticated)
|
|
}
|
|
formLogin { }
|
|
httpBasic { }
|
|
}
|
|
}
|
|
}
|
|
-----
|
|
====
|
|
|
|
This configuration explicitly sets up all the same things as our minimal configuration.
|
|
From here you can easily make the changes to the defaults.
|
|
|
|
You can find more examples of explicit configuration in unit tests, by searching https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[EnableWebFluxSecurity in the `config/src/test/` directory].
|
|
|
|
[[jc-webflux-multiple-filter-chains]]
|
|
=== Multiple Chains Support
|
|
|
|
You can configure multiple `SecurityWebFilterChain` instances to separate configuration by ``RequestMatcher``s.
|
|
|
|
For example, you can isolate configuration for URLs that start with `/api`, like so:
|
|
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
@Configuration
|
|
@EnableWebFluxSecurity
|
|
static class MultiSecurityHttpConfig {
|
|
|
|
@Order(Ordered.HIGHEST_PRECEDENCE) <1>
|
|
@Bean
|
|
SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) {
|
|
http
|
|
.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**")) <2>
|
|
.authorizeExchange((exchanges) -> exchanges
|
|
.anyExchange().authenticated()
|
|
)
|
|
.oauth2ResourceServer(OAuth2ResourceServerSpec::jwt); <3>
|
|
return http.build();
|
|
}
|
|
|
|
@Bean
|
|
SecurityWebFilterChain webHttpSecurity(ServerHttpSecurity http) { <4>
|
|
http
|
|
.authorizeExchange((exchanges) -> exchanges
|
|
.anyExchange().authenticated()
|
|
)
|
|
.httpBasic(withDefaults()); <5>
|
|
return http.build();
|
|
}
|
|
|
|
@Bean
|
|
ReactiveUserDetailsService userDetailsService() {
|
|
return new MapReactiveUserDetailsService(
|
|
PasswordEncodedUser.user(), PasswordEncodedUser.admin());
|
|
}
|
|
|
|
}
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Configuration
|
|
@EnableWebFluxSecurity
|
|
open class MultiSecurityHttpConfig {
|
|
@Order(Ordered.HIGHEST_PRECEDENCE) <1>
|
|
@Bean
|
|
open fun apiHttpSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
|
return http {
|
|
securityMatcher(PathPatternParserServerWebExchangeMatcher("/api/**")) <2>
|
|
authorizeExchange {
|
|
authorize(anyExchange, authenticated)
|
|
}
|
|
oauth2ResourceServer {
|
|
jwt { } <3>
|
|
}
|
|
}
|
|
}
|
|
|
|
@Bean
|
|
open fun webHttpSecurity(http: ServerHttpSecurity): SecurityWebFilterChain { <4>
|
|
return http {
|
|
authorizeExchange {
|
|
authorize(anyExchange, authenticated)
|
|
}
|
|
httpBasic { } <5>
|
|
}
|
|
}
|
|
|
|
@Bean
|
|
open fun userDetailsService(): ReactiveUserDetailsService {
|
|
return MapReactiveUserDetailsService(
|
|
PasswordEncodedUser.user(), PasswordEncodedUser.admin()
|
|
)
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first
|
|
<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` will only apply to URL paths that start with `/api/`
|
|
<3> Specify the authentication mechanisms that will be used for `/api/**` endpoints
|
|
<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs
|
|
<5> Specify the authentication mechanisms that will be used for the rest of the application
|
|
|
|
Spring Security will select one `SecurityWebFilterChain` `@Bean` for each request.
|
|
It will match the requests in order by the `securityMatcher` definition.
|
|
|
|
In this case, that means that if the URL path starts with `/api`, then Spring Security will use `apiHttpSecurity`.
|
|
If the URL does not start with `/api` then Spring Security will default to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request.
|
|
|