WebFlux Security

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

Minimal WebFlux Security Configuration

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

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 保护,等等。

Explicit WebFlux Security Configuration

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

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.

该配置显式地设置的所有内容与我们的最小配置相同。从这里,您可以更容易地对默认值进行更改。

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

Multiple Chains Support

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

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

  • 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 使用 @Order`配置 `SecurityWebFilterChain,以指定要由 Spring Security 首先生成的 SecurityWebFilterChain
2 使用 `PathPatternParserServerWebExchangeMatcher`来指定此 `SecurityWebFilterChain`仅适用于以 `/api/`开头的 URL 路径
3 指定要用于 `/api/**`端的身份验证机制
4 创建另一个优先级较低的 `SecurityWebFilterChain`实例,以匹配所有其他 URL
5 指定要用于其余应用程序的身份验证机制

Spring Security 为每个请求选择一个 SecurityWebFilterChain @Bean。它按 securityMatcher 定义的顺序匹配请求。

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