如何使用JavaConfig从Spring Security中删除角色前缀?

如何使用JavaConfig从Spring Security中删除角色前缀?,spring,spring-security,spring-java-config,Spring,Spring Security,Spring Java Config,我正在尝试删除Spring Security中的“角色”前缀。我尝试的第一件事是: http.servletApi().rolePrefix(""); 这不起作用,所以我尝试按照中的建议创建BeanPostProcessor。那也没用 最后,我尝试创建自己的SecurityExpressionHandler: @Override protected void configure(HttpSecurity http) throws Exception { http

我正在尝试删除Spring Security中的“角色”前缀。我尝试的第一件事是:

http.servletApi().rolePrefix("");
这不起作用,所以我尝试按照中的建议创建
BeanPostProcessor
。那也没用

最后,我尝试创建自己的
SecurityExpressionHandler

  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http
          .authorizeRequests()
          .expressionHandler(webExpressionHandler())
          .antMatchers("/restricted").fullyAuthenticated()
          .antMatchers("/foo").hasRole("mycustomrolename")
          .antMatchers("/**").permitAll();
  }

  private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
      DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
      defaultWebSecurityExpressionHandler.setDefaultRolePrefix("");
      return defaultWebSecurityExpressionHandler;
  }
@覆盖
受保护的无效配置(HttpSecurity http)引发异常{
http
.授权请求()
.expressionHandler(webExpressionHandler())
.antMatchers(“/restricted”).fullyaauthenticated()
.antMatchers(“/foo”).hasRole(“mycustomrolename”)
.antMatchers(“/**”).permitAll();
}
私有SecurityExpressionHandler webExpressionHandler(){
DefaultWebSecurityExpressionHandler DefaultWebSecurityExpressionHandler=新的DefaultWebSecurityExpressionHandler();
defaultWebSecurityExpressionHandler.setDefaultRolePrefix(“”);
返回defaultWebSecurityExpressionHandler;
}
然而,这也不起作用。如果我使用“hasAuthority(roleName)”而不是
hasRole
,它将按预期工作


是否可以从Spring Security的hasRole检查中删除角色前缀?

以下配置适用于我

@Override
public void configure(WebSecurity web) throws Exception {
    web.expressionHandler(new DefaultWebSecurityExpressionHandler() {
        @Override
        protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
            WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
            root.setDefaultRolePrefix(""); //remove the prefix ROLE_
            return root;
        }
    });
}

从Spring 4.2开始,您可以使用单个bean定义前缀,如下所述:

XML版本:

<beans:bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
    <beans:constructor-arg value="" />
</beans:bean>

如果您是4.2之前的版本,并且使用所谓的投票者(如果您使用@hasRole等注释,那么您需要在上下文中定义以下bean:

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

@Bean
public DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler() {
    DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
    defaultWebSecurityExpressionHandler.setDefaultRolePrefix("");
    return defaultWebSecurityExpressionHandler;
}
这些bean用于为拼写表达式创建计算上下文,并且将defaultRolePrefix设置为“ROLE_3;”。尽管这取决于您的用例。这一个对我有用,而上面的没有

编辑:回答关于xml配置的问题->当然可以用xml完成。在java配置中完成的一切都可以用xml配置编写。下面是一个例子(虽然我没有测试它,所以可能有输入错误或其他原因):


新的
GrantedAuthorityDefaults
似乎将更改
DefaultWebSecurityExpressionHandler
DefaultMethodSecurityExpressionHandler
的前缀,但它不会修改从
@EnableGlobalMethodSecurity
设置的
角色引用

RoleVoter.rolePrefix用于方法安全的
@Secured(“ADMIN”)
风格

因此,除了
GrantedAuthorityDefaults
,我还必须添加这个
CustomGlobalMethodSecurity
类来覆盖
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;
    }
}

如果您使用SpringBoot2,您可以创建这个bean来覆盖前缀

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

我为我发布总结工作解决方案:

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

在Spring Boot 2.3中,我在启动时遇到了这个异常:

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
以下是我的解决方案:

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

奇怪的是,
BeanPostProcessor
对我有效(您确实将其声明为
静态
bean方法,并包含了
PriorityOrdered
,因此它运行得很早?)对于表达式处理程序也是如此。我们还有一个
DefaultMethodSecurityExpressionHandler
DefaultMethodSecurityExpressionHandler`配置了前缀设置
null
。是的,我直接从文档中复制了
BeanPostProcessor
的代码。我尝试将
@Bean
放在我的
@Configuration
类中,以实现Spring安全性和
@SpringBootApplication
类中。我添加了一个
System.out.println
,以确保在Spring Security之前也对其进行了配置
hasAuthority
按预期工作,因此我想我将使用它。我们在非spring启动应用程序中使用了它。这可能是干扰,还是引导的安全性在某种程度上仍在早期配置?XML配置中是否有任何等效的配置?我已经用XML配置更新了我的答案。。。但正如我所写,可能有某种错误-我没有测试出来。一般规则是-java配置中的所有内容都可以在xml中完成。在引导过程中,JHipster应用程序中出现故障,出现
org.springframework.beans.factory.BeanCreationException:。。。。。。。;嵌套异常是java.lang.IllegalArgumentException:需要ServletContext来配置默认的servlet处理
Petr-这只是一个猜测,但如果出现此错误,可能意味着您没有web上下文,因此不需要第二个bean-DefaultWebSecurityExpressionHandler。无论如何,每种配置都是不同的,所以很难判断您的案例中到底是什么问题。对我来说,这两个豆子解决了这个问题。没有为我工作过。没有工作过:见第四条有问题的评论。授权机构和角色之间有区别。此答案适用于GrantedAuthority。对于那些对注释有异议的人:将@Bean实例从安全配置移动到MVC配置参考:它适用于
HttpServletRequest.isUserInRole(String)
,但不适用于
@Secured(String)
。我在WebSecurityConfigurerAdapter中使用@EnableGlobalMethodSecurity,如何访问AccessDecisionManager?@Ninja AccessDecisionManager必须在一个额外的类中配置,因为我不相信它可以通过WebSecurity配置适配器完成。我认为您只需要创建一个扩展GlobalMethodSecurityConfiguration的新配置类,但这只有在使用
@Secured
注释时才有帮助,因为
@Secured
值在
RoleVoter
类中计算,和
@PreAuthorize
注释表达式在
PreInvocationAuthorizationAdviceVoter
类中求值,发布另一个bean
新的GrantedAuthorityDefaults(“”
),在构造函数中使用前缀参数,这也会影响
@PreAuthorize
@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
    }
}
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
@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 
}