【问题标题】:SpelEvaluationException: EL1004E:(pos 0): Method call: Method hasPermission(java.lang.String) cannot be found on MethodSecurityExpressionRoot typeSpelEvaluationException: EL1004E:(pos 0): 方法调用:在 MethodSecurityExpressionRoot 类型上找不到方法 hasPermission(java.lang.String)
【发布时间】:2014-06-02 23:17:07
【问题描述】:

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

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(<generated>)
    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

谁能指出我在这里做错了什么?

更新

我是这样使用注解@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;
    }

}

【问题讨论】:

    标签: java spring spring-mvc spring-security


    【解决方案1】:

    好的,我终于开始完成我的项目的这一部分了。 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.");
        }
    
    }
    

    【讨论】:

    • 我遇到了和你一样的错误。即使我添加了hasPermission(Authentication arg0, Object arg1) 方法,但它仍然不起作用。你有什么办法吗?
    【解决方案2】:

    然后我解决了这里提出的问题,在我的控制器的方法中更改了对 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 的正确参数,它返回一个空值,但这是另一个主题的主题)。

    【讨论】:

      【解决方案3】:
      ... 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 方法的代码。我应该如何补充方法调用以匹配我拥有的实现?或者,如果我添加一个带有 1 个参数的方法,我如何从登录用户那里获取权限列表?有什么想法吗?
      【解决方案4】:

      你没有在你使用hasPermission('admin_main')的地方显示代码。

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

      boolean hasPermission(Authentication authentication, Object permission);
      

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

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

      【讨论】:

      • 我快了一秒:-P
      • 我在主题中添加了我使用 hasPermission 方法的代码。我应该如何补充方法调用以匹配我拥有的实现?或者,如果我添加一个带有 1 个参数的方法,我如何从登录用户那里获取权限列表?有什么想法吗?
      猜你喜欢
      • 1970-01-01
      • 2021-12-30
      • 1970-01-01
      • 2017-03-11
      • 2019-07-14
      • 1970-01-01
      • 2012-05-22
      • 1970-01-01
      • 2021-09-03
      相关资源
      最近更新 更多