@PreAuthorize如何在Reactive Application中工作或如何在没有ThreadLocal的情况下生效?

时间:2017-10-17 14:59:36

标签: spring-security spring-webflux

您能解释处理@PreAuthorize("hasRole('ADMIN')")的建议在Reactive应用程序中检索SecurityContext的位置吗?

以下Spring Security示例很好地说明了这种用法:https://github.com/spring-projects/spring-security/tree/5.0.0.M4/samples/javaconfig/hellowebflux-method

在检查了Spring Security Webflux源代码之后,我发现了SecurityContextRepository的一些实现,但是load方法需要ServerWebExchange作为参数。

我正在尝试了解如何在标准服务中替换SecurityContextHolder.getContext().getAuthentication()调用(因为ThreadLocal不再是Reactive Application中的选项),但我不明白如何替换它拨打SecurityContextRepository,但ServerWebExchange没有参考。

3 个答案:

答案 0 :(得分:6)

你是对的,ThreadLocal不再是一个选项,因为请求的处理不依赖于特定的线程。

目前,Spring Security将身份验证信息存储为ServerWebExchange属性,因此与当前请求/响应对相关联。但是,当您无法直接访问当前交易所时,仍需要该信息,例如@PreAuthorize

身份验证信息存储在Reactive管道中(可以从MonoFlux访问),这是一个非常有趣的Reactor功能 - 管理与特定{{1}相关联的上下文(在Web应用程序中,HTTP客户端正在从服务器提取数据并且这样做)。

我不知道相当于Subscriber或某种从上下文中获取身份验证信息的快捷方法。

详细了解Reactor Context feature in the reference documentation。 您还可以看到that being used in Spring Security here的示例。

答案 1 :(得分:5)

ReactiveSecurityContextHolder以反应方式提供身份验证,类似于SecurityContextHolder

它的getContext()方法提供了Mono<SecurityContext>,就像SecurityContextHolder.getContext()提供了SecurityContext一样。

ReactiveSecurityContextHolder
                    .getContext()
                    .map(context ->
                            context.getAuthentication()

答案 2 :(得分:1)

我实现了JwtAuthenticationConverter(kotlin):

val authFilter = AuthenticationWebFilter(ReactiveAuthenticationManager {
    authentication: Authentication -> Mono.just(authentication)
})
authFilter.setAuthenticationConverter(jwtAuthenticationConverter)

http.addFilterAt( authFilter, SecurityWebFiltersOrder.AUTHENTICATION)

然后我像这样设置一个SecurityConfig:

first_name = input("enter your first name\n")
last_name = input("enter your last name\n")
first_name = first_name.lower()
last_name = last_name.lower()
def rev(s):
    str = ""
    for i in s:
       str = i + str
    return str
first_name = rev(first_name)
last_name = rev(last_name)
first_name = first_name[0].upper() + first_name[1:]
last_name = last_name[0].upper() + last_name[1:]
print(first_name + " " + last_name)

您可以使用此方法自定义AuthenticationConverter,就像我对基于jwt的身份验证所做的那样,以设置所需的身份验证对象。