【问题标题】:Spring Security & Multipart requestsSpring Security 和多部分请求
【发布时间】:2013-02-10 02:23:23
【问题描述】:

我有一个受 Spring Security 和 OAuth2 保护的 @Controller,我试图让我的用户上传文件:

@Controller
@RequestMapping(value = "/api/image")
public class ImageController {

    @PreAuthorize("hasAuthority('ROLE_USER')")
    @RequestMapping(value = "/upload", method = RequestMethod.PUT)
    public @ResponseBody Account putImage(@RequestParam("title") String title, MultipartHttpServletRequest request, Principal principal){
        // Some type of file processing...
        System.out.println("-------------------------------------------");
        System.out.println("Test upload: " + title);
        System.out.println("Test upload: " + request.getFile("file").getOriginalFilename());
        System.out.println("-------------------------------------------");

        return ((Account) ((OAuth2Authentication) principal).getPrincipal());
    }
}

当我尝试上传文件和标题时,出现以下异常。我将 Content-Type 标头设置为 multipart/form-data。

java.lang.IllegalStateException: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ org.apache.catalina.connector.RequestFacade@1aee75b7]]
    at org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver.resolveArgument(ServletRequestMethodArgumentResolver.java:84)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)

如何在 Spring Security 后面进行文件上传?似乎请求永远不会变成 M​​ultiPartHttpServerRequest,所以它不起作用?

如果我将方法签名更改为采用 @RequestParam MultipartFile,则会收到如下异常:

DEBUG DefaultListableBeanFactory - Returning cached instance of singleton bean 'imageController'
DEBUG ExceptionHandlerExceptionResolver - Resolving exception from handler [public com.tinsel.server.model.Account com.tinsel.server.controller.ImageController.putImage(java.lang.String,org.springframework.web.multipart.MultipartFile,java.security.Principal)]: java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
DEBUG ResponseStatusExceptionResolver - Resolving exception from handler [public com.tinsel.server.model.Account com.tinsel.server.controller.ImageController.putImage(java.lang.String,org.springframework.web.multipart.MultipartFile,java.security.Principal)]: java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
DEBUG DefaultHandlerExceptionResolver - Resolving exception from handler [public com.tinsel.server.model.Account com.tinsel.server.controller.ImageController.putImage(java.lang.String,org.springframework.web.multipart.MultipartFile,java.security.Principal)]: java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
DEBUG DispatcherServlet - Could not complete request
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
    at org.springframework.util.Assert.notNull(Assert.java:112)

...但我确实在我的 XML 中配置了 MultipartResolver:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="268435456"/> <!-- 256 megs -->
</bean>

我确实看到了this blog post about getting this working under Spring 3.0 - 但我正在努力保持最新状态,目前正在使用 3.1。是否有更新的修复?

【问题讨论】:

    标签: spring file-upload spring-security oauth-2.0


    【解决方案1】:

    问题是我使用的是 PUT 而不是 POST。 Commons FileUpload 被硬编码为只接受文件的 POST 请求。

    在那里查看isMultipartContent method。要解决此问题,请使用 POST 或扩展该类并覆盖该方法以按您喜欢的方式工作。

    我为此问题打开了FILEUPLOAD-214。

    【讨论】:

    • FILEUPLOAD-214 已通过 WONTFIX 解决。根据作者的说法,PUT 不应与 Multipart 一起使用
    • 是的,最终我确实更改为 POST 而不是 PUT。
    • 1.3版本已修复
    • 在 1.3.1 中使用 3 年后,它仍然存在 - only POST。
    • 这个问题仍然存在。这是一个微小的变化,不会破坏 任何 HTTP 规范(它破坏了 REST,值得注意的是,它不是 HTTP,因此没有定义多部分请求或PUT,可以在这里安全地忽略),然而……人们坚持不这样做。因为某些原因。很高兴看到愚蠢无处不在。
    【解决方案2】:

    为了解决这个问题,不要使用spring MultiPartHttpServerRequest,而是将请求作为HttpServletRequest,使用apache commons fileupload库解析来自PUT方法的请求,并处理文件。以下是一些示例代码:

    ServletFileUpload fileUpload = new ServletFileUpload(new DiskFileItemFactory());
    List<FileItem> fileItems = fileUpload.parseRequest(httpServletRequest);
    InputStream in = fileItems.get(0).getInputStream();
    ...
    

    【讨论】:

    • 如何在 HTTPRequest 中获取文件请帮忙:P
    【解决方案3】:

    在 Config.groovy 中

    确保启用多部分,

    // whether to disable processing of multi part requests
       grails.web.disable.multipart=false
    

    在控制器中添加 Post 方法

    def upload(){
        MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
        if(request instanceof MultipartHttpServletRequest)
                {
                    CommonsMultipartFile f = (CommonsMultipartFile) mpr.getFile("myFile");
                    println f.contentType
                    f.transferTo()
                    if(!f.empty)
                        flash.message = 'success'
                    else
                        flash.message = 'file cannot be empty'
                }
        else
        flash.message = 'request is not of type MultipartHttpServletRequest'}
    

    有了这些,我就可以上传文件了,与 Spring Security 没有任何关系。

    【讨论】:

      【解决方案4】:

      您可以查看https://github.com/joshlong/the-spring-tutorial,其中有一个示例演示如何在启用 Spring Security OAuth 的情况下发布到 Spring MVC。我什至使用 HTML5 拖放将图像拖到屏幕上,然后通过 ajax 将其提交到服务器。

      【讨论】:

        猜你喜欢
        • 2014-09-30
        • 1970-01-01
        • 2014-02-19
        • 1970-01-01
        • 1970-01-01
        • 2019-08-08
        • 2015-10-04
        • 2012-08-12
        相关资源
        最近更新 更多