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。但是,目前我们仅支持表达式的Booleanboolean的返回类型。这意味着该表达式不能阻塞。

当与第 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中找到完整的示例