# 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)
}
}
```