# EnableReactiveMethodSecurity Spring 安全性支持使用[反应堆的背景](https://projectreactor.io/docs/core/release/reference/#context)的方法安全性,其设置使用`ReactiveSecurityContextHolder`。例如,这演示了如何检索当前登录的用户消息。 | |要使其工作,方法的返回类型必须是`org.reactivestreams.Publisher`(即`Mono`/`Flux`),或者函数必须是 Kotlin 协程函数。
这是与反应器的`Context`积分所必需的。| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 爪哇 ``` Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_USER"); Mono 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(); ``` Kotlin ``` val authentication: Authentication = TestingAuthenticationToken("user", "password", "ROLE_USER") val messageByUsername: Mono = 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 findMessageByUsername(String username) { return Mono.just("Hi " + username); } ``` Kotlin ``` fun findMessageByUsername(username: String): Mono { 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); } } ``` Kotlin ``` @EnableReactiveMethodSecurity class SecurityConfig { @Bean fun userDetailsService(): MapReactiveUserDetailsService { val userBuilder: User.UserBuilder = User.withDefaultPasswordEncoder() val rob = userBuilder.username("rob") .password("rob") .roles("USER") .build() val admin = userBuilder.username("admin") .password("admin") .roles("USER", "ADMIN") .build() return MapReactiveUserDetailsService(rob, admin) } } ``` 考虑以下类: 爪哇 ``` @Component public class HelloWorldMessageService { @PreAuthorize("hasRole('ADMIN')") public Mono findMessage() { return Mono.just("Hello World!"); } } ``` Kotlin ``` @Component class HelloWorldMessageService { @PreAuthorize("hasRole('ADMIN')") fun findMessage(): Mono { return Mono.just("Hello World!") } } ``` 或者,使用 Kotlin 协程的下列类: Kotlin ``` @Component class HelloWorldMessageService { @PreAuthorize("hasRole('ADMIN')") suspend fun findMessage(): String { delay(10) return "Hello World!" } } ``` 结合上面的配置,`@PreAuthorize("hasRole('ADMIN')")`将确保`findByMessage`仅由具有`ADMIN`角色的用户调用。需要注意的是,标准方法安全性中的任何表达式都可以用于`@EnableReactiveMethodSecurity`。但是,此时我们只支持返回类型为`Boolean`或`boolean`的表达式。这意味着表达式不能阻塞。 当与[WebFlux 安全性](../configuration/webflux.html#jc-webflux)集成时,反应器上下文由 Spring 安全性根据经过身份验证的用户自动建立。 爪哇 ``` @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(exchanges -> exchanges .anyExchange().permitAll() ) .httpBasic(withDefaults()) .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); } } ``` Kotlin ``` @EnableWebFluxSecurity @EnableReactiveMethodSecurity class SecurityConfig { @Bean open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { return http { authorizeExchange { authorize(anyExchange, permitAll) } httpBasic { } } } @Bean fun userDetailsService(): MapReactiveUserDetailsService { val userBuilder: User.UserBuilder = User.withDefaultPasswordEncoder() val rob = userBuilder.username("rob") .password("rob") .roles("USER") .build() val admin = userBuilder.username("admin") .password("admin") .roles("USER", "ADMIN") .build() return MapReactiveUserDetailsService(rob, admin) } } ```