WebFlux 安全(Security)

本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

Spring Security的WebFlux支持依赖于 WebFilter,对Spring WebFlux和Spring WebFlux.Fn 的作用是一样的。一些示例应用程序演示了这些代码。

最小的WebFlux安全配置

下面的列表显示了一个最小的WebFlux安全配置。

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

明确的WebFlux安全配置

下面的显示了最小WebFlux安全配置的明确版本。

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 { }
        }
    }
}
确保你在你的 Kotlin 类中导入了 invoke 函数,有时IDE不会自动导入它,导致编译问题。

这个配置明确地设置了所有与我们的最小配置相同的东西。从这里,你可以更容易地对默认值进行修改。

你可以通过在 config/src/test/ 目录下搜索 EnableWebFluxSecurity ,找到更多单元测试中明确配置的例子。

Multiple Chain 的支持

你可以配置多个 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 配置一个带有 @OrderSecurityWebFilterChain,以指定 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,可以匹配任何请求。