mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-11-04 00:28:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			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.
 | 
						|
 |