我有一个简单的SpringBoot应用程序,具有使用自定义SecurityExpressionRoot的Web安全性和方法安全性配置。 当我从IDE中启动SB应用(例如STS或IDEA)并呼叫端点时,我会得到
org.springframework.expression.spel.SpelEvaluationException: EL1004E:
Method call: Method hasAnyAccess(java.lang.String) cannot be found on
org.springframework.security.access.expression.method.MethodSecurityExpressionRoot type
当我使用应用程序jar文件从CLI启动SB应用时,端点调用成功:
INFO 11282 --- [nio-8080-exec-4] c.e.CustomMethodSecurityExpressionRoot :
< CustomMethodSecurityExpressionRoot(): [org.springframework.security.authentication.UsernamePasswordAuthenticationToken@442a8f33: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 36E17CAA657E897B1682BFF27EA7DA1F; Granted Authorities: ROLE_USER]
INFO 11282 --- [nio-8080-exec-4] c.e.CustomMethodSecurityExpressionRoot :
> hasAnyAccess(): [[FULL_ACCESS]]
我们非常感谢您的帮助。
网络安全配置:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
}
方法安全配置:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler expressionHandler = new CustomMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
}
方法安全性表达式处理程序:
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
安全表达式根:
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
LOGGER.info("< CustomMethodSecurityExpressionRoot(): [{}]", authentication);
}
public final boolean hasAnyAccess(String... accessLevels) {
LOGGER.info("> hasAnyAccess(): [{}]", Arrays.asList(accessLevels));
return true;
}
}
其他控制器:
@RestController
@RequestMapping("/")
public class MyController {
@PreAuthorize("hasAnyRole('ROLE_USER') && hasAnyAccess('FULL_ACCESS')")
@RequestMapping(value = "hello", method = RequestMethod.GET)
public String hello(@RequestParam String name) {
return "Hello '" + name + "' at " + System.currentTimeMillis() + "\n";
}
}
更新1: 使用
启动SB应用程序时,也会发生相同的SpelEvaluationExceptionmvn spring-boot:run
更新2: 从日志看来,从IDE启动时,我的MethodSecurityConfig扩展名被GlobalMethodSecurityConfiguration覆盖:
INFO 5927 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
Overriding bean definition for bean 'methodSecurityInterceptor' with a different definition:
replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=methodSecurityConfig; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [com/example/MethodSecurityConfig.class]]
with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]]
INFO 5927 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
Overriding bean definition for bean 'methodSecurityMetadataSource' with a different definition:
replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=methodSecurityConfig; factoryMethodName=methodSecurityMetadataSource; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [com/example/MethodSecurityConfig.class]]
with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; factoryMethodName=methodSecurityMetadataSource; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]]
从JAR启动时,我的MethodSecurityConfig扩展覆盖了GlobalMethodSecurityConfiguration :
INFO 6092 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
Overriding bean definition for bean 'methodSecurityInterceptor' with a different definition:
replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]]
with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=methodSecurityConfig; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [com/example/MethodSecurityConfig.class]]
INFO 6092 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
Overriding bean definition for bean 'methodSecurityMetadataSource' with a different definition:
replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; factoryMethodName=methodSecurityMetadataSource; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]]
with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=methodSecurityConfig; factoryMethodName=methodSecurityMetadataSource; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [com/example/MethodSecurityConfig.class]]
答案 0 :(得分:0)
经过一番调查,结果发现两者都指定了@EnableGlobalMethodSecurity(prePostEnabled = true)
注释
WebSecurityConfigurerAdapter
扩展名和GlobalMethodSecurityConfiguration
扩展名引起问题。从WebSecurityConfigurerAdapter
中删除注释即可解决此问题。