Spring 反应式安全 |如何实现反应式 PermissionEvaluator

Posted

技术标签:

【中文标题】Spring 反应式安全 |如何实现反应式 PermissionEvaluator【英文标题】:Spring Reactive Security | How to implement a reactive PermissionEvaluator 【发布时间】:2018-10-30 04:46:29 【问题描述】:

假设我们有一个带注释的休息控制器方法:

@PreAuthorize("hasPermission(#username, 'USER_PROFILE', 'WRITE')")

在 Spring MVC 中,我们将实现 PermissionEvaluator 来实现隐藏在以下方法签名后面的授权

boolean hasPermission(
  Authentication authentication, 
  Serializable targetId, 
  String targetType,
  Object permission
)

这在使用 Spring WebFlux 时似乎仍然有效,只要您不需要在 hasPermission 方法中调用响应式服务/方法,我猜这种情况很少发生,因为您通常希望使用响应式接口你的数据库层也是如此。如果您无论如何都要在此方法中调用响应式服务,您将需要在某个时间在某些Mono 上调用block(),从而遇到麻烦,因为您是从响应式管道中调用的。

在来自 Josh Long 的关于 Spring WebFlux 安全性的教程中,他解释了如何通过提供自定义 ReactiveAuthorizationManagers 使用路径匹配器直接在 SecurityWebFilterchain 上实现授权。但是没有说明Spring WebFlux中如何使用PreAuthorize注解。

我期待实现一些ReactivePermissionEvaluator

Mono<Boolean> hasPermission(
  Authentication authentication, 
  Serializable targetId, 
  String targetType,
  Object permission
)

这也将允许在实现中使用反应式服务,但我无法找到 ReactiveAuthorizationManager 的任何实现,它会扫描 PreAuthorize 注释并将评估分配给反应式 PermissionEvaluator 也没有ReactivePermissionEvaluator 接口存在。

所以最后的问题是,如何实现一个响应式PermissionEvaluator,它允许调用响应式服务,例如不阻塞地查询数据库中的自动化信息?

【问题讨论】:

【参考方案1】:

遗憾的是...https://github.com/spring-projects/spring-security/issues/5046 中的 Spring Security 尚不支持此功能

【讨论】:

【参考方案2】:

您应该这样做。只需从 applicationContext 获取 DefaultMethodSecurityExpressionHandler bean 并显式替换 permissionsEvaluator。

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration 
@Autowire
private ApplicationContext applicationContext;

    @Bean
    @DependsOn("methodSecurityExpressionHandler")
    public SecurityWebFilterChain springSecurityFilterChain(
            ServerHttpSecurity http) 
        DefaultMethodSecurityExpressionHandler defaultWebSecurityExpressionHandler = this.applicationContext.getBean(DefaultMethodSecurityExpressionHandler.class);
        defaultWebSecurityExpressionHandler.setPermissionEvaluator(permissionEvaluator());
        return http.csrf().disable()
                .httpBasic().disable()
                .formLogin().disable()
                .logout().disable()
                .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
                .addFilterAt(tokenAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .authorizeExchange()
                .anyExchange().authenticated()
                .and().build();

    

   PermissionEvaluator permissionEvaluator() 
    return new PermissionEvaluator() 
        @Override
        public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) 
            //Custom logic to evaluate @PreAuthorize("hasPermission('123', '123')")
            return false;
        

        @Override
        public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) 
            //Custom logic to evaluate @PreAuthorize("hasPermission('123', '123','123')")
            return false;
        
    ;

【讨论】:

以上是关于Spring 反应式安全 |如何实现反应式 PermissionEvaluator的主要内容,如果未能解决你的问题,请参考以下文章

禁用执行器健康端点的 webflux(反应式)安全性

新一代Spring Web框架WebFlux!

弹簧反应的弹簧安全会话超时

Spring WebClient 使用简介

Spring WebClient 使用简介

Spring WebClient 使用简介