How do I remove the ROLE_ prefix from Spring Security with JavaConfig?

后端 未结 7 1077
灰色年华
灰色年华 2020-12-01 16:22

I\'m trying to remove the \"ROLE_\" prefix in Spring Security. The first thing I tried was:

http.servletApi().rolePrefix(\"\");

That didn\'

相关标签:
7条回答
  • 2020-12-01 16:48

    I post summary working solutions for me:

    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    
        /**
         * Allow skip ROLE_ when check permission using @Secured, like:
         *  @Secured({AuthorityConstants.ROLE_SYSTEM_ADMIN})
         */
        @Override
        protected AccessDecisionManager accessDecisionManager() {
            AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
            setAuthorityRolePrefix(accessDecisionManager, "");
            return accessDecisionManager;
        }
    
        private void setAuthorityRolePrefix(AffirmativeBased accessDecisionManager, String rolePrefix) {
            accessDecisionManager.getDecisionVoters().stream()
                    .filter(RoleVoter.class::isInstance)
                    .map(RoleVoter.class::cast)
                    .forEach(it -> it.setRolePrefix(rolePrefix));
        }
    
        /**
         * Allow skip ROLE_ when check permission using @PreAuthorize, like:
         * @PreAuthorize("hasAnyRole('USER', 'SYSTEM_ADMIN')")
         */
        @Bean
        GrantedAuthorityDefaults grantedAuthorityDefaults() {
            return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
        }
    }
    
    0 讨论(0)
  • 2020-12-01 16:51

    With Spring Boot 2.3 I got this exception at boot time:

    Error creating bean with name 'resourceHandlerMapping' defined in class path resource 
    [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]:
    Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
    Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: 
    Factory method 'resourceHandlerMapping' threw exception;
    nested exception is java.lang.IllegalStateException: No ServletContext set
    

    Here is my solution:

    @Configuration
    @Import(RolePrefixConfiguration.class)
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
      public static class RolePrefixConfiguration {
    
        @Bean
        public GrantedAuthorityDefaults grantedAuthorityDefaults() {
          log.debug("remove prefix 'ROLE_' from grantedAuthorityDefaults");
          return new GrantedAuthorityDefaults("");
        }
    
      }
       
       // ... your usual config 
    }
    
    0 讨论(0)
  • 2020-12-01 16:52

    It appears the new GrantedAuthorityDefaults will change the prefix for the DefaultWebSecurityExpressionHandler and the DefaultMethodSecurityExpressionHandler, but it doesn't modify the RoleVoter.rolePrefix that is setup from @EnableGlobalMethodSecurity.

    The RoleVoter.rolePrefix is what is used for @Secured("ADMIN") style of method security.

    So along with the GrantedAuthorityDefaults, I had to also add this CustomGlobalMethodSecurity class to override the defaults for RoleVoter.

    @Configuration
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public class CustomGlobalMethodSecurity extends GlobalMethodSecurityConfiguration {
    
        protected AccessDecisionManager accessDecisionManager() {
            AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
    
            //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;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 16:54

    Starting from Spring 4.2, you can define the prefix with a single bean, as described here: https://github.com/spring-projects/spring-security/issues/4134

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
    }
    

    XML version:

    <beans:bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
        <beans:constructor-arg value="" />
    </beans:bean>
    
    0 讨论(0)
  • 2020-12-01 16:56

    If you use Spring Boot 2, you can create this bean to override the RoteVoter prefix

    @Bean
    public GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return  new GrantedAuthorityDefaults("<anything you want>");
    }
    

    It works because when GlobalMethodSecurityConfiguration creates AccessDecisionManager in the method GlobalMethodSecurityConfiguration.accessDecisionManager(). Here is the snippet of code, notice the null check on grantedAuthorityDefaults

        protected AccessDecisionManager accessDecisionManager() {
        ....
        RoleVoter roleVoter = new RoleVoter();
        GrantedAuthorityDefaults grantedAuthorityDefaults =
                getSingleBeanOrNull(GrantedAuthorityDefaults.class);
        if (grantedAuthorityDefaults != null) {
            roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
        }
        decisionVoters.add(roleVoter);
        decisionVoters.add(new AuthenticatedVoter());
        return new AffirmativeBased(decisionVoters);
    }
    
    0 讨论(0)
  • 2020-12-01 17:01

    If you are prior to 4.2 and are using so called voters (you are if you use annotations like @hasRole etc) then you need to define below beans in the context:

    @Bean
    public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
        DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
        defaultMethodSecurityExpressionHandler.setDefaultRolePrefix("");
        return defaultMethodSecurityExpressionHandler;
    }
    
    @Bean
    public DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler() {
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setDefaultRolePrefix("");
        return defaultWebSecurityExpressionHandler;
    }
    

    These beans are used to create evaluation context for spell expressions and they have a defaultRolePrefix set to 'ROLE_'. Although it depends on your use case. This one worked for me and above didn't.

    EDIT: answering question about xml configuration -> of course it can be done in xml. Everything done in java config can be written in xml configuration. Here is example (although I did not test it so there might be a typo or something):

    <bean id="defaultWebSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
            <property name="defaultRolePrefix" value=""></property>
    </bean>
    
    <bean id="defaultMethodSecurityExpressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
            <property name="defaultRolePrefix" value=""></property>
    </bean>
    
    0 讨论(0)
提交回复
热议问题