22. EnableReactiveMethodSecurity
Spring Security 使用Reactor's Context支持方法安全性,而Reactor's Context是使用ReactiveSecurityContextHolder
设置的。例如,这演示了如何检索当前登录用户的消息。
Note
为此,该方法的返回类型必须为org.reactivestreams.Publisher
(即Mono
/Flux
)。这是与 Reactor 的Context
集成的必要条件。
Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_USER");
Mono<String> messageByUsername = ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(this::findMessageByUsername)
// In a WebFlux application the `subscriberContext` is automatically setup using `ReactorContextWebFilter`
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
StepVerifier.create(messageByUsername)
.expectNext("Hi user")
.verifyComplete();
this::findMessageByUsername
定义为:
Mono<String> findMessageByUsername(String username) {
return Mono.just("Hi " + username);
}
下面是在响应式应用程序中使用方法安全性时的最小方法安全性配置。
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Bean
public MapReactiveUserDetailsService userDetailsService() {
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
UserDetails rob = userBuilder.username("rob")
.password("rob")
.roles("USER")
.build();
UserDetails admin = userBuilder.username("admin")
.password("admin")
.roles("USER","ADMIN")
.build();
return new MapReactiveUserDetailsService(rob, admin);
}
}
考虑以下类别:
@Component
public class HelloWorldMessageService {
@PreAuthorize("hasRole('ADMIN')")
public Mono<String> findMessage() {
return Mono.just("Hello World!");
}
}
结合以上配置,@PreAuthorize("hasRole('ADMIN')")
将确保findByMessage
仅由具有ADMIN
角色的用户调用。重要的是要注意,标准方法安全性中的任何表达式都适用于@EnableReactiveMethodSecurity
。但是,目前我们仅支持表达式的Boolean
或boolean
的返回类型。这意味着该表达式不能阻塞。
当与第 16 章,WebFlux 安全集成时,Spring Security 将根据已认证的用户自动构建 Reactor 上下文。
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
return http
// Demonstrate that method security works
// Best practice to use both for defense in depth
.authorizeExchange()
.anyExchange().permitAll()
.and()
.httpBasic().and()
.build();
}
@Bean
MapReactiveUserDetailsService userDetailsService() {
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
UserDetails rob = userBuilder.username("rob")
.password("rob")
.roles("USER")
.build();
UserDetails admin = userBuilder.username("admin")
.password("admin")
.roles("USER","ADMIN")
.build();
return new MapReactiveUserDetailsService(rob, admin);
}
}
您可以在hellowebflux-method中找到完整的示例