2013-02-25 3 views
23

Ho un @Controller protetto con Primavera di sicurezza e OAuth2 in cui sto cercando di lasciare che i miei utenti di caricare un file:Primavera Sicurezza e Multipart richieste

@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()); 
    } 
} 

Quando provo a caricare un file e il titolo, io ottieni la seguente eccezione. Sto impostando l'intestazione Content-Type su 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) 

Come posso eseguire il caricamento di file dietro Spring Security? Sembra che la richiesta non venga mai trasformata in MultiPartHttpServerRequest e quindi non funziona?

Se cambio il mio metodo firma di prendere un @RequestParam MultipartFile, tanto sono un'eccezione come:

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) 

... ma ho un MultipartResolver configurato nel mio XML:

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

Ho visto this blog post about getting this working under Spring 3.0 - ma sto cercando di rimanere aggiornato e sto usando 3.1 al momento. C'è forse una correzione aggiornata?

risposta

24

Il problema è che sto usando un PUT anziché un POST. Commons FileUpload è hardcoded per accettare solo le richieste POST per i file.

Controllare il isMultipartContent method lì. Per risolvere questo problema, usa un POST o estendi quella classe e sostituisci quel metodo per lavorare come preferisci.

Ho aperto FILEUPLOAD-214 per questo problema.

+4

FILEUPLOAD-214 è stato risolto con WONTFIX. Secondo gli autori, 'PUT' non dovrebbe essere usato con' Multipart' – beerbajay

+1

Sì, e alla fine sono passato a un POST piuttosto che a PUT. –

+0

È stato risolto nella versione 1.3 – thomaux

-1

si potrebbe dare un'occhiata a https://github.com/joshlong/the-spring-tutorial che ha un esempio che dimostra come pubblicare su Spring MVC con Spring Security OAuth abilitato. Uso persino il trascinamento HTML5 per trascinare l'immagine sullo schermo e inviarla tramite ajax al server.

3

Per risolvere il problema, non utilizzare spring MultiPartHttpServerRequest, anziché richiedere la richiesta come HttpServletRequest, utilizzando la libreria di fileupload di apache commons per analizzare la richiesta dal metodo PUT e elaborare il file. Qui ci sono alcuni esempi di codice:

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

In Config.groovy

Assicurarsi multipart è abilitata,

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

In Controller Aggiungi metodo 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'} 

con questi, è stato in grado di caricare il file, niente relativo Spring Security.