Spring自定义授权无法使用@PreAuthorize

Posted

技术标签:

【中文标题】Spring自定义授权无法使用@PreAuthorize【英文标题】:Spring custom Authorization not working using @PreAuthorize 【发布时间】:2014-05-16 08:52:09 【问题描述】:

我正在尝试在我的 spring (3.2.2) mvc 应用程序中实现自定义 @PreAuthorize 方法。但是,每当我单击应该将我带到实现@PreAuthorize 的控制器方法的链接时,它都会给我这个错误:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:948)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)


root cause 

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
    org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:339)
    org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:198)
    org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    com.nav.qanda.admin.question.controller.AdminQuestionController$$EnhancerByCGLIB$$5bcda356_2.handleRequest(<generated>)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:606)
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

这是我的 app-servlet.xml

  <security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler" />
  </security:global-method-security>

  <bean id="expressionHandler" class="com.nav.panda.security.PandaMethodSecurityExpressionHandler" />

这些是覆盖的 java 文件

public class PandaMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler
      @Override
      protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
              MethodInvocation invocation)
        PandaMethodSecurityExpressionRoot root = new PandaMethodSecurityExpressionRoot(authentication);
        root.setThis(invocation.getThis());
        return root;
      



public class PandaMethodSecurityExpressionRoot implements MethodSecurityExpressionOperations 


    private Object filterObject;
    private Object returnObject;
    private Object target;


    public  boolean adminOnly() 
        System.out.println("Checking admin authority");
        return true;
//     return  this.hasAuthority("ADMIN");
     ... other methods

控制器看起来像这样:

@RequestMapping(value = "/createPandaPage", method = RequestMethod.GET)
      @PreAuthorize("adminOnly()")
      public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException 
           return new ModelAndView("admin/createPanda");
       

web.xml:

<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 </filter>

 <filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping> 

我的应用程序中的登录将从我的应用程序中填充一个用户对象(它具有从数据库读取填充的用户权限)。如何通过此用户对象来检查权限?而且,我还需要做什么才能使其正常工作?

【问题讨论】:

【参考方案1】:

导致该方法被调用的请求需要经过Spring Security过滤器链,否则在权限检查时将没有可用的安全上下文。

没有看到堆栈跟踪的其余部分,我不能说 100%,但看起来这就是这里发生的事情,考虑到您看到的异常(如果您搜索错误消息,您应该会发现类似的问题)。

因此,您需要确保您想要保护的所有请求都由安全过滤器链处理,并且您的过滤器链配置正确(如果您使用命名空间,它应该自动配置)。

【讨论】:

我已经用完整的堆栈跟踪更新了这个问题。我如何确保(除了发布的代码)请求正在通过 Spring Security 过滤器?以及如何告诉 Spring 我的 User 对象是需要检查用户权限的对象。 我用 spring 安全过滤器映射(更新的问题)更新了我的 web.xml,现在我的应用程序根本没有加载 有没有一个例子展示了如何使用自定义授权注释以及自定义身份验证机制,这将与 Spring Security 一起使用?

以上是关于Spring自定义授权无法使用@PreAuthorize的主要内容,如果未能解决你的问题,请参考以下文章

spring boot spring security 基于自定义令牌的身份验证和自定义授权

使用 Spring Security 自定义 Http 授权标头

Spring Boot 自定义授权标头请求根本没有通过

认证与授权Spring Security自定义页面

认证与授权Spring Security自定义页面

在 spring-security 的身份验证中无法获取自定义信息