Disable EnableGlobalMethodSecurity annotation

后端 未结 3 665
耶瑟儿~
耶瑟儿~ 2020-12-06 20:58

Is there a way I can disable the global method security using the boolean securityEnabled from my config.properties? Any other approach?

@EnableWebSecurity          


        
相关标签:
3条回答
  • 2020-12-06 22:00

    I've managed this by defining a Spring "securityDisabled" profile and conditionally applying security config based off that. I'm using Spring Boot 2.0.2. I believe this should work if not using Spring Boot and in previous versions of Spring Boot, but I have not tested. It's possible some tweaks may be required to property and class names because I know in Spring 2.0 some of that changed.

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

    Then my security config looks like this:

    @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
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-06 22:01

    Thanks to Rob Winch for the solution. For folks who would like to do something similar but with prePostEnabled i have tried and tested the below similar approach and works just fine.

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

    EDIT: In addition to above i realized it is required to add following beans to the class. The below will help using the expression based pre invocation checks along with avoiding "ROLE_" prefix that is defaulted in all the handlers

    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;
    }
    
    0 讨论(0)
  • 2020-12-06 22:02

    The easiest way to do this is:

    • Extract method security to its own class
    • Remove the securedEnabled attribute entirely
    • Override the customMethodSecurityMetadataSource method and return the result based on the configured value.

    For example:

    @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;
        }    
    }
    
    0 讨论(0)
提交回复
热议问题