mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-27 12:48:44 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			245 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			7.6 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.
 | |
| A few sample applications demonstrate the code:
 | |
| 
 | |
| * 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
 | |
| 
 | |
| The following listing shows a minimal WebFlux Security configuration:
 | |
| 
 | |
| .Minimal WebFlux Security Configuration
 | |
| [tabs]
 | |
| ======
 | |
| 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);
 | |
| 	}
 | |
| }
 | |
| -----
 | |
| 
 | |
| 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)
 | |
|     }
 | |
| }
 | |
| -----
 | |
| ======
 | |
| 
 | |
| This configuration provides form and HTTP basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default login page and a default logout page, sets up security related HTTP headers, adds CSRF protection, and more.
 | |
| 
 | |
| == Explicit WebFlux Security Configuration
 | |
| 
 | |
| The following page shows an explicit version of the minimal WebFlux Security configuration:
 | |
| 
 | |
| .Explicit WebFlux Security Configuration
 | |
| [tabs]
 | |
| ======
 | |
| 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"]
 | |
| -----
 | |
| import org.springframework.security.config.web.server.invoke
 | |
| 
 | |
| @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 { }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| -----
 | |
| ======
 | |
| 
 | |
| [NOTE]
 | |
| Make sure to import the `org.springframework.security.config.web.server.invoke` function to enable the Kotlin DSL in your class, as the IDE will not always auto-import the method, causing compilation issues.
 | |
| 
 | |
| This configuration explicitly sets up all the same things as our minimal configuration.
 | |
| From here, you can more easily make changes to the defaults.
 | |
| 
 | |
| You can find more examples of explicit configuration in unit tests, by searching for 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` instances.
 | |
| 
 | |
| For example, you can isolate configuration for URLs that start with `/api`:
 | |
| 
 | |
| [tabs]
 | |
| ======
 | |
| 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"]
 | |
| ----
 | |
| import org.springframework.security.config.web.server.invoke
 | |
| 
 | |
| @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 selects one `SecurityWebFilterChain` `@Bean` for each request.
 | |
| It matches the requests in order by the `securityMatcher` definition.
 | |
| 
 | |
| In this case, that means that, if the URL path starts with `/api`, Spring Security uses `apiHttpSecurity`.
 | |
| If the URL does not start with `/api`, Spring Security defaults to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request.
 | |
| 
 |