【问题标题】:Disable EnableGlobalMethodSecurity annotation禁用 EnableGlobalMethodSecurity 注释
【发布时间】:2014-04-06 05:46:51
【问题描述】:

有没有一种方法可以使用 config.properties 中的布尔 securityEnabled 禁用全局方法安全性?还有其他方法吗?

@EnableWebSecurity 
@EnableGlobalMethodSecurity(securedEnabled=true) 
@PropertySource("classpath:config.properties")  
public class SecurityConfig 
  extends WebSecurityConfigurerAdapter {    

  @Value("${securityconfig.enabled}") 
  private boolean securityEnabled;

  ...

}

【问题讨论】:

  • 你必须通过注释来做?在 XML 配置文件中有一种简单的方法
  • 我更喜欢将我的所有配置与 spring java config 一起使用

标签: java spring spring-security


【解决方案1】:

最简单的方法是:

  • 将方法安全性提取到自己的类中
  • 完全删除securedEnabled属性
  • 重写 customMethodSecurityMetadataSource 方法并根据配置的值返回结果。

例如:

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

【讨论】:

  • 行得通!只有几个 cmets,a) 如果 securityenabled 为 false,我返回 null 和 b) 在我的从 AbstractAnnotationConfigDispatcherServletInitializer 扩展的 serverlet 初始化程序类的 getRootConfigClasses() 方法中,我需要同时传递 SecurityConfig.class 和 MethodSecurityConfig.class。
  • 谢谢我显然错过了我的例子中的空值。我更新了示例以反映这一点。
  • @RobWinch 这不适用于最新的 SpringBoot 版本。
【解决方案2】:

我通过定义 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
    }
  }
}

【讨论】:

  • 完美干净的解决方案。
  • 我以同样的方式结束。唯一的缺点是它变得非常混乱,不平凡的配置......大部分都是复制的。
【解决方案3】:

在 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);
    }

}

【讨论】:

    【解决方案4】:

    感谢 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 ;
    }}
    

    编辑:除上述之外,我意识到需要将以下 bean 添加到类中。下面将帮助使用基于表达式的预调用检查以及避免所有处理程序中默认的“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;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-08
      • 2018-08-25
      • 2017-06-02
      • 2021-08-17
      • 2019-10-25
      • 2015-06-25
      • 2017-06-19
      • 1970-01-01
      • 2015-07-06
      相关资源
      最近更新 更多