Java 禁用EnableGlobalMethodSecurity批注

Java 禁用EnableGlobalMethodSecurity批注,java,spring,spring-security,Java,Spring,Spring Security,是否有一种方法可以使用config.properties中的boolean securityEnabled禁用全局方法安全性?还有别的办法吗 @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled=true) @PropertySource("classpath:config.properties") public class SecurityConfig extends WebSecurityConfigurer

是否有一种方法可以使用config.properties中的boolean securityEnabled禁用全局方法安全性?还有别的办法吗

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

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

  ...

}

最简单的方法是:

  • 将方法安全性提取到它自己的类
  • 完全删除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;
    }    
}

最简单的方法是:

  • 将方法安全性提取到它自己的类
  • 完全删除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;
    }    
}

我通过定义一个Spring“securityDisabled”配置文件并在此基础上有条件地应用安全配置来管理这一点。我使用的是SpringBoot2.0.2。我相信如果不使用SpringBoot和以前版本的SpringBoot,这应该是可行的,但我还没有测试过。可能需要对属性名和类名进行一些调整,因为我知道在Spring2.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
    }
  }
}

我通过定义一个Spring“securityDisabled”配置文件并在此基础上有条件地应用安全配置来管理这一点。我使用的是SpringBoot2.0.2。我相信如果不使用SpringBoot和以前版本的SpringBoot,这应该是可行的,但我还没有测试过。可能需要对属性名和类名进行一些调整,因为我知道在Spring2.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
    }
  }
}

感谢Rob Winch提供的解决方案。对于那些想做类似事情但使用prespenabled的人,我已经尝试并测试了下面类似的方法,效果很好

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

感谢Rob Winch提供的解决方案。对于那些想做类似事情但使用prespenabled的人,我已经尝试并测试了下面类似的方法,效果很好

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

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

}

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

}

你必须通过注释来完成吗?有一种简单的方法可以在XML配置文件中实现,我更喜欢将所有配置与spring java配置一起使用,您必须通过注释来实现吗?有一种简单的方法可以在XML配置文件中实现这一点,我更喜欢将我所有的配置与SpringJavaConfig一起使用!只需几条注释,a)如果securityenabled为false,我返回null,b)在servelet初始值设定项类的getRootConfigClasses()方法中,该类从AbstractAnnotationConfigDispatchersServletInitializer扩展而来,我需要传递SecurityConfig.class和MethodSecurityConfig.class。谢谢,我在我的示例中显然没有传递null。我更新了示例以反映这一点。@这在最新的SpringBoot版本中不起作用。这很有效!只需几条注释,a)如果securityenabled为false,我返回null,b)在servelet初始值设定项类的getRootConfigClasses()方法中,该类从AbstractAnnotationConfigDispatchersServletInitializer扩展而来,我需要传递SecurityConfig.class和MethodSecurityConfig.class。谢谢,我在我的示例中显然没有传递null。我更新了示例以反映这一点。这不适用于最新的SpringBoot版本。完美而干净的解决方案。我以同样的方式结束。唯一的缺点是,它变得非常混乱与非琐碎的配置。。。大部分都是复制的。完美而干净的解决方案。我以同样的方式结束。唯一的缺点是,它变得非常混乱与非琐碎的配置。。。大部分都是复制的。