【问题标题】:How to use PreAuthorize with async Spring MVC controller如何将 PreAuthorize 与异步 Spring MVC 控制器一起使用
【发布时间】:2014-01-18 17:46:06
【问题描述】:

我有一个 Spring MVC 服务,可以让我上传文件。它使用来自 Spring Security 的@PreAuthorize 来处理对资源的访问控制。控制器通过 Callable 使用 Servlet 3 异步 servlet。

@PreAuthorize("...")
@RequestMapping(value = "upload", method = RequestMethod.PUT)
public Callable<ResponseEntity> upload(final InputStream inputStream)
{
    return new Callable<ResponseEntity>()
    {
        @Override
        public ResponseEntity call() throws Exception
        {
            ...
        }
    };
}

服务中的某处 - 在我的代码之外 - 正在引发异常。

An Authentication object was not found in the SecurityContext

cglib 为我的 Spring 控制器生成的代码似乎引发了异常。这是堆栈跟踪的大部分内容。

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:339) ~[spring-security-core-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:198) ~[spring-security-core-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60) ~[spring-security-core-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at com.testing.upload.controller.RESTService$$EnhancerByCGLIB$$66a0c4c9.upload(<generated>) ~[spring-core-3.2.4.RELEASE.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_65]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_65]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_65]
    at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_65]
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) ~[spring-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) ~[spring-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) ~[spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) ~[spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) ~[spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) ~[spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) ~[spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) [spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:849) [spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:758) [javax.servlet-3.0.0.v201112011016.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) [spring-webmvc-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848) [javax.servlet-3.0.0.v201112011016.jar:na]

我已根据 this blog post 底部关于 Spring Security 3.2 中的异步支持的说明更新了我的 web.xml。

最后,错误并不总是发生。只有当我尝试上传大文件时才会出现这种情况。这让我觉得它确实与试图使控制器成为异步控制器有关。

版本:

  • 春季 3.2.4
  • Spring 安全 3.2
  • cglib 3.1
  • Java Servlet 3.0
  • Java 6
  • 8 号码头

【问题讨论】:

    标签: java spring spring-mvc spring-security servlet-3.0


    【解决方案1】:

    如果上传发生在衍生线程中,则安全上下文可能不可用。这是因为默认情况下安全上下文绑定到父线程,新的子线程不会知道它。

    您可以尝试将SecurityContextHolder 策略更改为InheritableThreadLocal,使其可用于衍生线程。

    您可以通过编程方式进行设置:

    SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
    

    或者在 Spring XML 配置中:

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetClass"
            value="org.springframework.security.core.context.SecurityContextHolder"/>
        <property name="targetMethod" value="setStrategyName"/>
        <property name="arguments"><list><value>MODE_INHERITABLETHREADLOCAL</value></list></property>
    </bean>
    

    或者您可以在启动应用时设置系统属性:

    -Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL
    

    【讨论】:

    • 不幸的是,这对我不起作用。我看到了同样的错误。
    • 您使用了三种策略设置机制中的哪一种?
    • 我尝试了 XML 和编程方法。对于编程方法,我将构造函数中的调用放入 Spring MVC 控制器的构造函数中。
    猜你喜欢
    • 2017-02-17
    • 2011-08-19
    • 2017-04-12
    • 2014-07-30
    • 1970-01-01
    • 2020-11-13
    • 2016-01-14
    • 1970-01-01
    • 2011-05-26
    相关资源
    最近更新 更多