【问题标题】:Spring Reactive Security | How to implement a reactive PermissionEvaluatorSpring 反应式安全 |如何实现反应式 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,它允许调用响应式服务,例如不阻塞地查询数据库中的自动化信息?

【问题讨论】:

    标签: spring-security spring-webflux


    【解决方案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;
              }
          };
      }
      

      【讨论】:

        猜你喜欢
        • 2020-07-26
        • 2020-10-27
        • 2020-07-19
        • 2022-12-19
        • 2020-04-28
        • 2019-10-25
        • 1970-01-01
        • 2018-02-08
        • 2021-07-16
        相关资源
        最近更新 更多