2013-02-25 96 views
23

我與春天有安全和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[ [email protected]]] 
    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後面上傳文件?看起來這個請求永遠不會變成MultiPartHttpServerRequest,所以它不起作用?

如果我改變我的方法簽名採取@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) 

...但我有一個MultipartResolver在我的XML配置:

<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。是否有更新的修復程序?

回答

24

問題是我正在使用PUT而不是POST。 Commons FileUpload被硬編碼爲只接受文件的POST請求。

檢查isMultipartContent method那裏。要解決這個問題,可以使用POST或擴展該類並覆蓋該方法以使其符合您的喜好。

我爲此問題打開了FILEUPLOAD-214

+4

FILEUPLOAD-214已用WONTFIX解決。根據作者'PUT'不應該與'Multipart'一起使用 – beerbajay 2014-04-14 14:28:48

+1

是的,最終我確實改用了POST而不是PUT。 – 2014-04-14 17:57:06

+0

它已經在1.3版中修復了 – thomaux 2015-12-28 10:38:11

-1

您可以看看https://github.com/joshlong/the-spring-tutorial,它有一個演示如何在啓用Spring Security OAuth的情況下發布到Spring MVC的示例。我甚至使用HTML5拖放將圖像拖放到屏幕上,然後通過ajax將其提交給服務器。

3

要解決此問題,請不要使用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(); 
... 
2

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沒有任何關係。