从IDE启动SprinBoot应用程序-SpelEvaluationException

时间:2018-10-13 10:55:03

标签: spring-boot spring-security

我有一个简单的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应用程序时,也会发生相同的SpelEvaluationException
mvn 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]]

1 个答案:

答案 0 :(得分:0)

经过一番调查,结果发现两者都指定了@EnableGlobalMethodSecurity(prePostEnabled = true)注释

  • WebSecurityConfigurerAdapter扩展名和
  • GlobalMethodSecurityConfiguration扩展名

引起问题。从WebSecurityConfigurerAdapter中删除注释即可解决此问题。