禁用启用全局方法安全注释



有没有办法使用布尔安全性禁用全局方法安全性启用从我的配置属性?还有其他方法吗?

@EnableWebSecurity 
@EnableGlobalMethodSecurity(securedEnabled=true) 
@PropertySource("classpath:config.properties")  
public class SecurityConfig 
  extends WebSecurityConfigurerAdapter {    
  @Value("${securityconfig.enabled}") 
  private boolean securityEnabled;
  ...
}

最简单的方法是:

  • 将方法安全性提取到其自己的类中
  • 完全删除已启用的安全属性
  • 重写自定义方法安全元数据源方法,并根据配置的值返回结果。

例如:

@EnableWebSecurity
@Configuration
@PropertySource("classpath:config.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}
@EnableGlobalMethodSecurity
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Value("${securityconfig.enabled}")
    private boolean securityEnabled;
    protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
        return securityEnabled ? new SecuredAnnotationSecurityMetadataSource() : null;
    }    
}

我通过定义一个 Spring "securityDisabled" 配置文件并基于它有条件地应用安全配置来管理它。我正在使用 Spring Boot 2.0.2。 我相信如果不使用 Spring Boot 和以前版本的 Spring Boot,这应该可以工作,但我还没有测试过。 可能需要对属性和类名进行一些调整,因为我知道在 Spring 2.0 中其中一些发生了变化。

// In application.properties
spring.profiles.include=securityDisabled

然后我的安全配置如下所示:

@Configuration
public class SecurityConfig {
  // When the securityDisabled profile is applied the following configuration gets used
  @Profile("securityDisabled")
  @EnableWebSecurity
  public class SecurityDisabledConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Configure http as needed from Spring Security defaults when
        // NO security is desired
    }
  }
  // When the securityDisabled profile is NOT applied the following configuration gets used
  @Profile("!securityDisabled")
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  @EnableWebSecurity
  public class SecurityEnabledConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Configure http as needed from Spring Security defaults when
        // security is desired
    }
  }
}

在 Springboot2 中,一个简单的解决方案是在安全性关闭时将安全方法拦截器替换为虚拟拦截器:

@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Value("${disableSecurity}")
    private boolean disableSecurity;  
    public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
        return disableSecurity ? new SimpleTraceInterceptor()
                : super.methodSecurityInterceptor(methodSecurityMetadataSource);
    }
}

感谢 Rob Winch 提供的解决方案。对于想要做类似事情但使用 prePostEnabled 的人,我已经尝试并测试了以下类似的方法并且工作正常。

@EnableGlobalMethodSecurity(securedEnabled = true)
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
  @Value("${security.prePostEnabled}")
  private boolean prePostEnabled;
 @Autowired
private DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
  protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
     return prePostEnabled ? new PrePostAnnotationSecurityMetadataSource(new ExpressionBasedAnnotationAttributeFactory(defaultMethodSecurityExpressionHandler)) : null ;
}}

编辑:除了上面之外,我意识到需要将以下豆子添加到类中。以下内容将有助于使用基于表达式的预调用检查,同时避免所有处理程序中默认的"ROLE_"前缀

protected AccessDecisionManager accessDecisionManager() {
    AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
    ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
    expressionAdvice.setExpressionHandler(getExpressionHandler());
    //This is required in order to allow expression based Voter to allow access
    accessDecisionManager.getDecisionVoters()
            .add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
    //Remove the ROLE_ prefix from RoleVoter for @Secured and hasRole checks on methods
    accessDecisionManager.getDecisionVoters().stream()
            .filter(RoleVoter.class::isInstance)
            .map(RoleVoter.class::cast)
            .forEach(it -> it.setRolePrefix(""));
    return accessDecisionManager;
}
/**
 * Allow skip ROLE_ when check permission using @PreAuthorize, like:
 * @PreAuthorize("hasAnyRole('USER', 'SYSTEM_ADMIN')")
 * Added all the Beans
 */
@Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
    DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
    defaultMethodSecurityExpressionHandler.setDefaultRolePrefix("");
    return defaultMethodSecurityExpressionHandler;
}

最新更新