SpelEvaluationException:EL1004E:(pos 0):方法调用:在MethodSecurityExpressionRoot类型上找不到方法hasPermission(java.lang.String)

我向我的项目添加了一个类CustomPermissionEvaluator,由配置类MethodSecurityConfig配置,但是当我尝试运行我的应用程序时,在我通知我的登录证书后,我收到此错误消息:

Grave: Servlet.service() for servlet [dispatcher] in context with path [/webapp2] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Failed to evaluate expression 'hasPermission('admin_main')'] with root cause org.springframework.expression.spel.SpelEvaluationException: EL1004E:(pos 0): Method call: Method hasPermission(java.lang.String) cannot be found on org.springframework.security.access.expression.method.MethodSecurityExpressionRoot type at org.springframework.expression.spel.ast.MethodReference.findAccessorForMethod(MethodReference.java:202) at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:118) at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:80) at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:98) at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:11) at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:41) at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:54) at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:24) at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62) at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206) at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631) at com.spring.webapp.lojavirtual.acesso.controller.PrivadoController$$EnhancerByCGLIB$$e6bb4ae6_2.admin() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827) at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) 

我的类CustomPermissionEvaluator是:

 @Component public class CustomPermissionEvaluator implements PermissionEvaluator { public CustomPermissionEvaluator() { } @Override public boolean hasPermission(Authentication arg0, Object arg1, Object arg2) { System.out.println("CustomPermissionEvaluator.hasPermission"); if (arg0 == null || !arg0.isAuthenticated()) return false; else return arg0.getAuthorities().contains(arg1); } @Override public boolean hasPermission(Authentication arg0, Serializable arg1, String arg2, Object arg3) { throw new RuntimeException("Id-based permission evaluation not currently supported."); } } 

我的配置类MethodSecurityConfig是:

 @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { protected MethodSecurityExpressionHandler createExpressionHandler() { System.out.println("MethodSecurityConfig.createExpressionHandler"); DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator()); return expressionHandler; } } 

我的安全层的完整代码可以在这里找到:

https://github.com/klebermo/webapp2/tree/master/src/com/spring/webapp/lojavirtual/config/security

任何人都可以指出我在这里做错了什么?

UPDATE

我以这种方式使用注释@PreAuthorize:

 @Controller @RequestMapping(value="privado") public class PrivadoController { @RequestMapping(value="admin") @PreAuthorize("hasPermission('admin_main')") public ModelAndView admin() { ModelAndView mav = new ModelAndView(); mav.setViewName("privado/admin"); return mav; } @RequestMapping(value="customer") @PreAuthorize("hasPermission('customer_main')") public ModelAndView customer() { ModelAndView mav = new ModelAndView(); mav.setViewName("privado/customer"); return mav; } } 

好的,最后我开始完成我项目的这部分工作。 CustomPermissionEvaluator的最终代码是:

 @Component public class CustomPermissionEvaluator implements PermissionEvaluator { public CustomPermissionEvaluator() { } public boolean hasPermission(Authentication arg0, Object arg1) { System.out.println("CustomPermissionEvaluator.hasPermission"); System.out.println("arg0 = "+arg0); System.out.println("arg1 = "+arg1); if (arg0 == null || !arg0.isAuthenticated()) { System.out.println("false"); return false; } else { System.out.println("true"); for(GrantedAuthority authority: arg0.getAuthorities()) { if(authority.getAuthority().equals(arg1)) return true; } return false; } } @Override public boolean hasPermission(Authentication arg0, Object arg1, Object arg2) { System.out.println("CustomPermissionEvaluator.hasPermission"); System.out.println("arg0 = "+arg0); System.out.println("arg1 = "+arg1); System.out.println("arg2 = "+arg2); if (arg0 == null || !arg0.isAuthenticated()) { System.out.println("false"); return false; } else { System.out.println("true"); for(GrantedAuthority authority: arg0.getAuthorities()) { if(authority.getAuthority().equals(arg2)) return true; } return false; } } @Override public boolean hasPermission(Authentication arg0, Serializable arg1, String arg2, Object arg3) { throw new RuntimeException("Id-based permission evaluation not currently supported."); } } 
 ... Method hasPermission(java.lang.String) cannot be found ... 

方法hasPermission()在任何时候只用一个参数调用,但是你提供了3个和4个参数:

 public boolean hasPermission(Authentication arg0, Object arg1, Object arg2) public boolean hasPermission(Authentication arg0, Serializable arg1, String arg2, Object arg3) 

添加方法public boolean hasPermission(String permission)然后重试。

您不显示使用hasPermission('admin_main')

尽管它仍然是错误的:您的CustomPermissionEvaluator没有带单个参数的方法。 或者像Spring Security这样:

 boolean hasPermission(Authentication authentication, Object permission); 

也许你想使用hasRole('admin_main') ?..

主要的问题是你没有为方法实现提供足够的参数。

然后我解决了这里提出的问题,在我的控制器的方法中改变了对hasPermission的调用。 它们的最终代码是:

 @Controller @RequestMapping(value="privado") public class PrivadoController { @RequestMapping(value="admin") @PreAuthorize("hasPermission(#usuario, 'admin_main')") public ModelAndView admin() { ModelAndView mav = new ModelAndView(); mav.setViewName("privado/admin"); return mav; } @RequestMapping(value="customer") @PreAuthorize("hasPermission(#usuario, 'customer_main')") public ModelAndView customer() { ModelAndView mav = new ModelAndView(); mav.setViewName("privado/customer"); return mav; } } 

(现在我正在尝试找到替换#usuario的正确参数,它返回一个空值,但这是另一个主题的主题)。