WebFlux Security

Spring Security 的 WebFlux 支持依赖于 WebFilter,并且对于 Spring WebFlux 和 Spring WebFlux.Fn 来说工作原理相同。几个示例应用程序演示了该代码:

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:

Minimal WebFlux Security Configuration

下面的清单展示了最小的 WebFlux Security 配置:

The following listing shows a minimal WebFlux Security configuration:

Minimal WebFlux Security Configuration
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class HelloWebfluxSecurityConfig {

	@Bean
	public MapReactiveUserDetailsService userDetailsService() {
		UserDetails user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("user")
			.roles("USER")
			.build();
		return new MapReactiveUserDetailsService(user);
	}
}
@Configuration
@EnableWebFluxSecurity
class HelloWebfluxSecurityConfig {

    @Bean
    fun userDetailsService(): ReactiveUserDetailsService {
        val userDetails = User.withDefaultPasswordEncoder()
                .username("user")
                .password("user")
                .roles("USER")
                .build()
        return MapReactiveUserDetailsService(userDetails)
    }
}

该配置提供了表单和 HTTP 基本验证,设置授权才能要求经过验证的用户才能访问任何页面,设置了默认登录页面和默认注销页面,设置了与安全相关的 HTTP 标头,添加了 CSRF 保护,等等。

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

以下页面展示了最小 WebFlux Security 配置的显式版本:

The following page shows an explicit version of the minimal WebFlux Security configuration:

Explicit WebFlux Security Configuration
  • Java

  • Kotlin

@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();
	}
}
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 { }
        }
    }
}

Make sure that you import the invoke function in your Kotlin class, sometimes the IDE will not auto-import it 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.

您可以在单元测试中找到更多显式配置示例,方法是在 config/src/test/ 目录中搜索 link:https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[EnableWebFluxSecurity

You can find more examples of explicit configuration in unit tests, by searching for EnableWebFluxSecurity in the config/src/test/ directory.

Multiple Chains Support

您可以配置多个 SecurityWebFilterChain 实例以按 RequestMatcher 实例对配置进行分离。

You can configure multiple SecurityWebFilterChain instances to separate configuration by RequestMatcher instances.

例如,您可以为以 /api 开头的 URL 隔离配置:

For example, you can isolate configuration for URLs that start with /api:

  • Java

  • Kotlin

@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());
    }

}
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 为每个请求选择一个 SecurityWebFilterChain @Bean。它按 securityMatcher 定义的顺序匹配请求。

Spring Security selects one SecurityWebFilterChain @Bean for each request. It matches the requests in order by the securityMatcher definition.

在这种情况下,这意味着如果 URL 路径以 /api 开头,则 Spring Security 将使用 apiHttpSecurity。如果 URL 没有以 /api 开头,则 Spring Security 将默认为 webHttpSecurity,其中有一个隐含的 securityMatcher,它匹配任何请求。

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.