Spring security Spring被动安全性|如何实现被动许可评估器

Spring security Spring被动安全性|如何实现被动许可评估器,spring-security,spring-webflux,Spring Security,Spring Webflux,假设我们得到一个带注释的rest控制器方法: @PreAuthorize("hasPermission(#username, 'USER_PROFILE', 'WRITE')") 在SpringMVC中,我们将实现一个PermissionEvaluator,以实现隐藏在以下方法签名后面的授权 boolean hasPermission( Authentication authentication, Serializable targetId, String targetType

假设我们得到一个带注释的rest控制器方法:

@PreAuthorize("hasPermission(#username, 'USER_PROFILE', 'WRITE')")
在SpringMVC中,我们将实现一个
PermissionEvaluator
,以实现隐藏在以下方法签名后面的授权

boolean hasPermission(
  Authentication authentication, 
  Serializable targetId, 
  String targetType,
  Object permission
)
在使用SpringWebFlux时,只要您不需要在hasPermission方法中调用反应式服务/方法,这似乎仍然有效,我想这种情况很少发生,因为您通常也希望在数据库层中使用反应式接口。如果您无论如何都要在这个方法中调用一个反应式服务,那么您将需要在某个时间调用一些
Mono
上的
block()
,因此会遇到麻烦,因为您是从反应式管道中调用的

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

我希望实现一些
ReactivePermissionEvaluator

Mono<Boolean> hasPermission(
  Authentication authentication, 
  Serializable targetId, 
  String targetType,
  Object permission
)
Mono拥有权限(
身份验证,
可序列化的targetId,
字符串targetType,
对象权限
)
这将允许在实现中使用反应式服务,但我无法找到任何
ReactiveAuthorizationManager
的实现,该实现将扫描
预授权
注释并将评估发送给反应式
许可评估者
ReactivePermissionEvaluator
接口存在


因此,最后的问题是,如何实现一个反应式
许可评估器
,它允许调用反应式服务,例如在不阻塞的情况下查询数据库中的自动化信息

遗憾的是。。。Spring Security在

中还不支持这一点,下面是您应该如何做到这一点。只需从applicationContext获取DefaultMethodSecurityExpressionHandler bean并显式替换PermissionsValuator

@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;
        }
    };
}