如何使用JavaConfig从Spring Security中删除角色前缀?
我正在尝试删除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
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
}